However, in the front end the call to the endpoint /sanctum/csrf-cookie is failing to set the CSRF cookie needed for subsequent calls to the API. Upon inspecting the browser request header to set the cookies, the following error is given:
This attempt to set a cookie via a set-cookie header was blocked because its domain attribute was invalid with regards to the current host url.
Having tried various different combinations of values for SANCTUM_STATEFUL_DOMAINS and SESSION_DOMAIN, I am no closer to resolving the issue.
Appreciate it if anyone can share some guidance on this.
The issue appears to be related to using 2 different domains between the frontend app and backend app.
I THINK perhaps SESSION_DOMAIN = 'fly.dev' needed to be SESSION_DOMAIN = '.fly.dev' (and perhaps put both domains in the list in SANCTUM_STATEFUL_DOMAINS?)
Did you by chance use Laravel Breeze at all, or was this setup more manually with Sanctum and a separate front-end application?
It looks like Breeze does this “hard work” for you, but you can manually roll through some steps to get this working with Sanctum and your own code (you just need to do user auth yourself instead of having Breeze do it for you).
So I have this working locally but there’s a LOT to get just right for this type of setup (not specific to Fly).
Please be sure, in addition to all the setup we discussed, that:
APP_URL is set correctly in each application instance (esp if you’re using Laravel in the frontend, but perhaps your frontend is using the wrong domain - one of the cookies seems to be using domain domain=.saeedbhuta.com; as part of the cookie creation
While I see that your make a request to /sanctum/csrf-cookie, the subsequent request to /login isn’t including it.
So, be sure the cookie domain is being set correctly in both frontend and backend apps. To that point, I suspect your APP_URL is not being set correctly and might be using a default value in your code base.
And that may resolve the axios issue as well. However be sure that axios is setting axios.defaults.withCredentials = true; as documented (I’m assuming you’re using axios!)
Thanks for taking the time to look into this. Appreciate it.
When you say “working locally”, I’m guessing this is on your local machine and not deployed to fly.io?
My application is working locally but not after deploying to fly.io.
Re. your first point, yes it was pointing to a different domain when you checked. I assumed that maybe my issue was related to the fly.dev domain so wanted to see if it would occur on a custom domain.
Just an update, I was finally able to get it working using my custom domain.
My knowledge of DNS is quite limited so I could be wrong but it appears that the cookie issues I was having were caused by the .fly.dev domain, maybe some limitations in being able set cookies for the domain.
So to summarise. I have two apps (separate codebases); a Laravel API and a VueJS front end.
The issue: the Laravel CSRF endpoint was unable to set the cookie when requested by the front end. This led to all subsequent requests from the front end to the back end failing due to the absence of the CSRF cookie.
I resolved this using a custom domain for both apps. In order to do this I had to allocate an IPv4 address for each app. I then used these IP addresses to configure subdomains for my apps (added them as CNAME records).
I followed the simple example here Dockerize Vue.js App — Vue.js to Dockerize my front end Vue app. I tried to do it using Nginx but I couldn’t get the configuration correct. In order fix the redirect issue (redirects return 404), you’ll need to change the following line:
CMD [ "http-server", "dist" ]
so that you pass in a proxy option (this implements a catchall redirect):
Turns out that indeed this won’t work on *.fly.dev domains. Two things:
This setup requires setting up your cookie domain as .fly.dev which would potentially allow that cookie to work on most sites hosted on fly if they don’t use a custom domain (not great!)
More directly the issue: The fly.dev domain is on the public suffix list which is treated specially
So, using a custom domain here is the answer.
Random notes:
You might also consider bundling this all up into one code base and shipping them together, so you can use the same domain for front and backend. If that makes sense for your application is very much up to you.
If your front-end can have a bit of backend code deploying alongside it, perhaps instead your frontend code can make AJAX requests to some server-side code running on the same domain. That backend code can make API requests to the API-only app using private networks, thus not exposing the API to the public internet (and getting around CORS requirements).
Frontend hosted at my-app.com can send AJAX to my-app.com/user, and that code can send API requests to my-app-api.com/user over private networks.
It’s a big of a different setup and again, depends on your needs and how everything is setup on your end. But something to consider!
Update: I turned this into an article explaining the whole thing in more details: Figuring out SPAs · Fly