Reputation: 2590
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')
Upvotes: 12
Views: 25707
Reputation: 1666
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.
Upvotes: 0
Reputation: 100
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.
Upvotes: 2
Reputation: 79
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.
Upvotes: 1
Reputation: 691
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'
)),
Upvotes: 16
Reputation: 1277
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.
Upvotes: 1
Reputation: 384
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);
}
}
Upvotes: 7