I finally figured it out.
First of all, the xhr and route filter were both configured correctly. The root cause of this problem was definitely a cookie issue.
The cookie domain for laravel_session was not initially set. Browsers interpret that to be a short-hand for "current domain". That is, app.mysite.com What I needed to do was explicitly set the value in Laravel's session.domain
configuration to be ".mysite.com" That way, the same session cookie becomes available to app.mysite.com, api.mysite.com, and any other sub-domains of mysite.com Problem solved!
That said, there were two gotchas that I tripped over on my way to this solution:
- The first was that cookies cannot be set for TLDs. I normally set up my development domain to be something like "mysite", leaving off the TLD. As far as DNS is concerned, that IS a TLD, and the cookies will fail. Once I changed my fake domain for development over to "mysite.dev", "mysite" was no longer a TLD, and the browser accepted cookies for it.
- The second was that I had to remove my session cookie from my browser before I could log in to the new and different domain. I don't know why this is the case, but remember to clear your session cookie out when doing this.
- Obviously, this is too much to ask your users to do. If you're putting this kind of change out into an already deployed site, you need to consider how to get your users migrated over to the cookie changes.
- Since Laravel session cookies are set with an expiry time not too far into the future, one option is to simply deploy such changes when your users are not very active and accept the app appearing to be broken until all session cookies have expired. Only your currently and recently active users will be affected and the "solution" is nice and easy. But your app is broken for a while.
- The other option is to change the name of the session cookie away from "laravel_session" at the same time that you change the cookie domain. This way, the new cookie sits beside the old one while the old ones expire and your app remains unbroken.