12

I have been trying to implement Laravel sanctum, but I am having this error "CSRF token mismatch" even though I followed everything that is said in the Laravel Sanctum documentation

cors.php config file

'paths' => [
    'api/*',
    'login',
    'logout',
    'sanctum/csrf-cookie'
],
'supports_credentials' => true,

kernal is added as per the documentation, so not wasting space by adding its code here

.env file

SESSION_DRIVER=cookie
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost

I am using Angular 9 as my frontend here

This is my interceptor

request = request.clone({
    withCredentials: true
})

This is how I send the request to Laravel

this.http.get<any>(url('sanctum/csrf-cookie')).subscribe(() => {
     this.http.post<any>(url('login'), { this.username, this.password })
         .subscribe(success => console.log(success), error => console.log(error))
})

Once the first route is hit I can confirm the creation of cookies, but the issue is with the second route ('/login')

6 Answers 6

16

I was able to resolve this issue by adding http:// before localhost in config/sanctum.php

From this

'stateful' => explode(',', env(
        'SANCTUM_STATEFUL_DOMAINS',
        'localhost,127.0.0.1'
)),

To this

'stateful' => explode(',', env(
            'SANCTUM_STATEFUL_DOMAINS',
            'http://localhost,127.0.0.1'
    )),
Sign up to request clarification or add additional context in comments.

Comments

7

You need to send x-csrf-token in the header, (Angular includes it automatically only in relative URLs not absolute)

You can create an interpreter to do this, something like this should work:

import {Injectable} from '@angular/core';
import {
  HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpXsrfTokenExtractor
} from '@angular/common/http';

import { Observable } from 'rxjs';

@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {
  headerName = 'X-XSRF-TOKEN';

  constructor(private tokenService: HttpXsrfTokenExtractor) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (req.method === 'GET' || req.method === 'HEAD') {
      return next.handle(req);
    }

    const token = this.tokenService.getToken();

    // Be careful not to overwrite an existing header of the same name.
    if (token !== null && !req.headers.has(this.headerName)) {
      req = req.clone({headers: req.headers.set(this.headerName, token)});
    }
    return next.handle(req);
  }
}

1 Comment

How can I use that in my HttpClient post request?
2

I have a similar problem in my case but only some users are having this problem. I solved my problem by changing SESSION_DOMAIN to .localhost in the session.php file under the config folder.

Comments

1

My problem was that I was accessing the api on port 8001. It worked when I add it (127.0.0.1:8001) to 'stateful' in config/sanctum.php.

Comments

1

In my case, this problem was solved in a strange way. I went to the Illuminate\Foundation\Http\Middleware\VerifyCsrfToken file and there on line 76 in the "handle" method inside the "if case" there was a line like this:

$this->tokensMatch($request);

For testing purposes, I returned this string

return response()->json($this->tokensMatch($request));

and surprisingly it will return a normal token. Then I returned everything to its place, and it is strange, but this error was no longer there.

Comments

0

If you tried all other solutions but can't find the issue, make sure you have not edited the session table in any way.

My issue was this piece of code in the migrations

$table->foreignId('user_id')->constrained(
    table: 'users',
    indexName: 'user_id'
)->nullable();

nullable() must be ran before constrained() to take effect.
This caused Laravel to fail inserting new columns into the table since the first insert statements has user_id=null.

Adding to the fact that Laravel's error are silent when it fails writing into the sessions table, and this issue is not easy to spot.

Other issues such as the db_user's authorizations lacking will give the same error so make sure to check the "sessions" table and that it is storing the data as intended then debug from there.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.