Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

whizx's avatar
Level 1

Laravel Sanctum Cookies Not Working

Hello, I'm using Axios in Angular to send a GET request to '/sanctum/csrf-cookie' to obtain cookies (XSRF-TOKEN, laravel_session). However, when I subsequently send a POST request to Laravel with these cookies, I receive a "419 Page Expired (CSRF Token Mismatch)" error. When I inspect the request headers, I can see that the cookies are being sent, but I'm still getting the 419 error. The issue is that it was working perfectly a week ago, but it started giving this error today.

Angular/index.component.ts:

const Request = axios.create({
    baseURL:'http:// localhost:8000',
    withCredentials: true
})
Request.get('/sanctum/csrf-cookie').then(() => {
        Request.post('/').then((e) => {
				console.log(e.data)
        })
})

Laravel/.env:

SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost
APP_URL=http:// localhost:8000
FRONTEND_URL=http:// localhost:4200

Laravel/cors.php:

'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
0 likes
8 replies
JussiMannisto's avatar

The CSRF token is not read from the cookie on the server side. That would not protect against CSRF at all since browsers automatically send the cookies on every request.

You need to send the token either in an X-CSRF-TOKEN header or in a _token parameter.

whizx's avatar
Level 1

@JussiMannisto I'm already sending XSRF-TOKEN and laravel_session in the Request Header, but the result is the same.

POST / HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Content-Length: 2
Content-Type: application/json
Cookie: SL_G_WPT_TO=tr; XSRF-TOKEN=eyJpdiI6Ik5kSjdhUWpWck5OeFdLa0poNXQ5L2c9PSIsInZhbHVlIjoicUQ1YkdnUDIyWWlRZTVxYXJqaEFRNTdySDF4bnE1YWhMZTYyQ1lzSWpCNTlkSm15b1JpNy9Ra3BFcDBGSE1zdWZ3c0RuS3ZRYWFNTXlyVmM4bGJrTzIwTzFqd3NxV1pPeUx3Qy8veGJoUVMrdVA2bmd0MmxTVTB2K25ZYWJaeTQiLCJtYWMiOiJhNTRhM2JjNGI3MGM5NDZkYmIzNDUzM2ViZTE1NzcxMmZlOGM0ZTJkZTVhODAyZjVmYjcwMmFiYzE3Y2Y4ZmMwIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6Ik5qOWppZVhwQ2s5NGNJRW5YamNBWXc9PSIsInZhbHVlIjoiQUxaSlg5Qll4UGVNQXVyT1NIUk9mR1FRL2xKclNEREpQMWI2YmZiaVhkVUZyQjBlZzRWdWtIdGFyb1JJL0o0UlE2ZUFzZGtqWjViMHJiWlpFTTh6ZFR1eFBWUml4RWszcUFDUXVpdTJ1ME5rUTgzOHBjMm5hZ3ZqQkhJMXY4TmkiLCJtYWMiOiIxZWM0MzVmODdmZDcyMmUwZmQ4NzY0Nzk0NDQyNjRlOGM1YjIwOTIzNDdjMGY1ZTI0M2VlNzkyNThkYzcwNWZhIiwidGFnIjoiIn0%3D
Host: http:// localhost:8000
Origin: http:// localhost:4200
Referer: http:// localhost:4200/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 OPR/102.0.0.0
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Opera GX";v="102"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
JussiMannisto's avatar

@whizx The token is only there as a cookie. That won't work. You need to have it as separate X-CSRF-TOKEN or X-XSRF-TOKEN header.

Axios should add the header automatically but it's not present. I see that your origin and host have different ports, so the request is same-site and not same-origin. This is probably the reason why it's not added automatically. You may have to tweak your Axios configuration, but I'm not sure how from the top of my head.

Here's the relevant documentation section: https://laravel.com/docs/10.x/csrf#csrf-x-xsrf-token

whizx's avatar
Level 1

@jussimannisto Thank You, I have solved the problem. In case others encounter the same issue, the solution is as follows: Firstly, send a GET request to the /sanctum/csrf-cookie endpoint to obtain the XSRF-TOKEN and Laravel session cookies. Then, add X-XSRF-TOKEN to the Axios headers and set its value to the value of XSRF-TOKEN.

const Request = axios.create({
      baseURL:config.BACKEND,
      headers:{
        "X-XSRF-TOKEN":this.Cookie.get('XSRF-TOKEN')
      },
      withCredentials:true
    })
JussiMannisto's avatar

@whizx Why Axios doesn't do this automatically still bothers me, so I checked the source code. Axios should set the X-XSRF-TOKEN header automatically for same-origin requests, but also if withCredentials is true. See the source code.

Can you check if your axios default config has the xsrfCookieName and xsrfHeaderName properties set correctly:

console.log(axios.defaults);

The values should be XSRF-TOKEN and X-XSRF-TOKEN, respectively.

Btw, having to add the token to every request is a chore. You might want to do something like this instead:

axios.defaults.headers.common['X-XSRF-TOKEN'] = this.Cookie.get('XSRF-TOKEN');
JussiMannisto's avatar

Nevermind, I think I figured it out. The source code I linked earlier was from an older version of Axios. The withCredentials condition has since been temporarily removed due to a newly discovered vulnerability. See this comment.

That change was made a week ago. I assume your XSRF header stopped working because you updated your Axios version.

ivqonsanada's avatar

@whizx also got this issue, its breaking change on the axios part, where it exlude the xsrf token even if you use withCredentials, you need to also add withXSRFToken: true, like this

const axios = Axios.create({
  baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
  },
  withCredentials: true,
  withXSRFToken: true,
})
1 like

Please or to participate in this conversation.