4
votes

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')

4

4 Answers

4
votes

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
votes

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'
    )),
0
votes

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.

0
votes

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.