Skip to content
Advertisement

CSRF Token Mismatch with Laravel API using Digital Ocean Load Balancer with Sticky Session

I am working on a project in Laravel 8 which I am now testing the deployment on production servers. I have set up 2 Digital Ocean Droplets that are behind a load balancer with Sticky Sessions enabled. I am attempting to login via a SPA app with a separate Laravel API so the middleware is configured for the api routes to be stateful API and perform CSRF validation. This works perfectly fine when I just hit a single droplet and bypass the load balancer but as soon as the load balancer is in use, I always receive a 419 CSRF Token mismatch.

Everything I found on Google says that the session needs to be shared between servers, but I don’t believe this is the case in this scenario. I have turned on sticky session with a cookie called DO-LB in the load balancer so all requests from the same session go to the same server, and I am tailing the Apache access log on both servers, and I can see all requests such as the get-csrf and the auth route (using Sanctum) both hit the same server so would I would still be getting a token mismatch.

I am also using the cookie session driver.

UPDATE

I’ve found something a little strange, if I point my DNS to a singled droplet I see the X-XSRF-TOKEN is sent as a request header, but if I change DNS to point to the load balancer then X-xSRF-TOKEN is not sent as a request header. I am using Axios to send the request but I can’t see how a load balancer can affect Axios

UPDATE 2

It looks like when I run it locally XSRF-TOKEN is not an HttpOnly cookie but when running it on production the XSRF-TOKEN is flagged as HttpOnly which from what I’ve read means its inaccessible from Javascript hence why Axios isn’t sending it. I seem to have confirmed this by doing Cookies.get(“XSRF-TOKEN”) and printing the result, locally it prints the token to the console, but in production its undefined.

UPDATE 3

I updated my Apache configuration to override the headers as a test to remove the HttpOnly flag which seems to have done the trick, and I can now see when I log in, Chrome sends an X-XSRF-TOKEN in the request even though I still get a CSRF Token Mismatch.

I’ve compared the string in the chrome cookie store with what is being sent in the X-XSRF-TOKEN and they both match so I don’t understand why Laravel keeps returning me a mismatch and I am at a complete loss.

Advertisement

Answer

I think I’ve figured this out, if it can be migrated to server fault then please do but I thought as figured out it makes to say what it was instead of just deleting.

I was using cloudflare and made the error of using self signed certificate between DO droplet and cloudflare and gave this cert to the load balancer. Although no errors were thrown by DO, in the Apache log I noticed that although the web site load, when an API request was made I noticed the apache error log Server name not provided via TLS extension (using default/first virtual host). Not sure if this is the actual cause but made me think if the issue was caused by the self signed certificate.

I generated a new origin server from Cloudflare which means it has a trusted CA and then gave that to DO load balancer and the problem went away.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement