Laravel CSRF Token Mismatch Post request from seperate React project - laravel

I have a React project and a seperate Laravel project, which communicate with eachother. But whenever I send a POST-request from React to Laravel, it gives me a CSRF Token Mismatch. Now if the form was inside my Laravel project, I could just add the token as a field in my form, but it's a seperate project so I'm not sure.
I tried to add the token in resources/js/bootstrap.js, because I'm using Axios. I changed the code to:
import axios from 'axios';
window.axios = axios;
window.Laravel = {csrfToken: '{{ csrf_token() }}'};
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = window.Laravel.csrfToken;
But it still doesn't work, how can I handle this?

First of all csrf work with web.php by default. So when you write a post request route within the web.php route file then you'll face csrf token problem.
Solution 1:
Whenever you're writing Rest APIs for SPA's or mobile apps. You should use api.php route file. Because in the api.php route file, some layers are excluded due to their stateless behavior.
If you use api.php route file then you don't need to send csrf token in request headers.
Solution 2:
if you're writing API in web.php then you need to add that route in App\Http\Middleware\VerifyCsrfToken middleware except array, like following:
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'stripe/*',
];
}
In this way, that route will not throw csrf related errors.
I hope that will helps you.

Related

Laravel: CSRF token not needed for login via axios

When I use a form to post to the /login route, a valid CSRF token is needed.
<form role="form" method="POST" action="/login">
However, I can login completely without the token simply using:
axios.post("/login", { email:this.email, password:this.password })
.then((res) => {
window.location.href = "/dashboard";
})
This is a security risk, right? Why is that? How can I fix it?
It's not a vulnerability. If you check your resources/js/bootstrap.js file, a comment explains this.
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
If you inspect the request made in the network tab of your browser's dev tools, you will see the XSRF-Token header.
just add this in your frontend.blade.php file head:
    
<meta name="csrf-token" content="{{ csrf_token() }}">
And in your bootstrap.js file it is
well protected by declaring and authorizing axios.

Laravel Sanctum CSRF returns 419 for unprotected routes

I have a SPA app where I try to implement Sanctum's CSRF protection.
From docs:
To authenticate your SPA, your SPA's "login" page should first make a request to the /sanctum/csrf-cookie endpoint to initialize CSRF protection for the application
Right now I request CSRF token before I login
axios.get('/sanctum/csrf-cookie').then(response => {
// Login...
});
Should I request CSRF token before doing ANY post request in my application?
If yes, I basically need to request a CSRF token before routes like POST api/password_reset, POST api/tracking, POST api/register etc.
Or is there any way to tell Laravel Sanctum to only return 419 CSRF token mismatch errors for protected routes, ie. routes with auth:sanctum middleware?
EDIT:
Just wanted to make it clear that I don't have an issue with CSRF implementation in general. It works great after I have requested the CSRF token. Axios will add the token in all subsequent requests. My question is really about when to do the first request to CSRF token.
I have searched for something similar and I stumbled upon this; Laravel: How to Avoid TokenMismatchException CSRF Token on certain routes using a method
You can therefore kindly exclude the routes from being checked for CSRF token by adding the route path in $except array in VerifyCsrfToken class inside the app/Http/Middleware/VerifyCsrfToken.php like shown below;
protected $except = [
'/api/password_reset',
'/api/tracking',
'/api/register',
];
This can be seen also in Laravel Official Documentation Excluding URIs From CSRF Protection

Laravel Sanctum CSRF Cookie Request Optional

I am trying to use Laravel Sanctum for my SPA. There are some basic home pages from web.php routes but other axios API interactions with the SPA are in api.php routes guarded by auth:sanctum
From the official documentation (https://laravel.com/docs/7.x/sanctum#spa-authenticating), it says we have to send a request to /sanctum/csrf-cookie to initialize CSRF protection prior login. However, I noticed that even without login, Laravel by default already initialized XSRF-TOKEN and <app_name>_session cookies to my browser. I do not need to initialize it via /sanctum/csrf-cookie and my subsequent API request in the logged-in SPA still works. Later I checked https://laravel.com/docs/7.x/csrf#csrf-x-xsrf-token and it says it is the default behavior that Laravel will include the CSRF token in each response.
My question is, is it true that /sanctum/csrf-cookie initialization is optional and it is safe for axios to use the default CSRF token return by Laravel? Or am I doing something wrong which exposes my SPA to CSRF attack?
Your main SPA home page is probably provided by a route that is defined in your web.php route file as you mentionned. In App/Http/Kernel.php, check in your middleware groups if there is VerifyCsrfToken::class defined as a middleware for web :
protected $middlewareGroups = [
'web' => [
...
StartSession::class,
...
VerifyCsrfToken::class,
...
]
]
This middleware is responsible for creating header response like : set-cookie XSRF-TOKEN=kgXZBZ4AccC0H17KEMw.... when you request any route available in web.php (if the cookie yet doesn't exist obviously), that will indeed initialize a XSRF-TOKEN cookie.
Therefore, you don't need to request route /sanctum/csrf-cookie when you already use this VerifyCsrfToken middleware.
However, if you are doing full SPA totally separated from your Laravel backend and deliver a html page differently, you won't have this XSRF-TOKEN cookie generated by default. Thus, as mentionned in Sanctum documentation, you need to request /sanctum/csrf-cookie to generate cookie before going further.

How to use Postman for Laravel $_POST request

How can I try sending a post request to a Laravel app with Postman?
Normally Laravel has a csrf_token that we have to pass with a POST/PUT request. How can I get and send this value in Postman? Is it even possible without turning off the CSRF protection?
Edit:
Ah wait, I misread the question. You want to do it without turning off the CSRF protection? Like Bharat Geleda said: You can make a route that returns only the token and manually copy it in a _token field in postman.
But I would recommend excluding your api calls from the CSRF protection like below, and addin some sort of API authentication later.
Which version of laravel are you running?
Laravel 5.2 and up:
Since 5.2 the CSRF token is only required on routes with web middleware. So put your api routes outside the group with web middleware.
See the "The Default Routes File" heading in the documentation for more info.
Laravel 5.1 and 5.2:
You can exclude routes which should not have CSRF protection in the VerifyCsrfToken middleware like this:
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'api/*',
];
}
See the "Excluding URIs From CSRF Protection" heading documentation for more info.
If you store your sessions in Cookies, you can grab the Cookie from an auth request in Developer Tools.
Copy and paste that Cookie in the Header of your POSTMAN or Paw requests.
This approach allows you to limit your API testing to your current session.
1.You can create a new route to show the csrf token using your controller with help of the function below.
(Use a Get request on the route)
public function showToken {
echo csrf_token();
}
2.Select the Body tab on postman and then choose x-www-form-urlencoded.
3.Copy the token and paste in postman as the value of the key named _token.
4.Execute your post request on your URL/Endpoint
In the headers, add the cookies, before making request, the XSRF-TOKEN cookie and the app cookie. I.e yourappname_session
In laravel, 5.3. Go to app/Http/Kernel.php find middlewareGroups then comment VerifyCsrfToken. Because it executes all middleware before service your request.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
***// \App\Http\Middleware\VerifyCsrfToken::class,***
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];

Get laravel CSRF token from outside laravel

I need to post a search form from classic asp to a laravel route. I can get the csrf token from the cookie, if there is one and put it into the form, but I don't know what to do if there is no csrf cookie?
Should I open laravel route that returns new csrf token or is that a security risk?
Is the only other option to remove the route I need to post to from csrf validation?
You can disable CSRF protection for specific route in VerifyCsrfToken middleware, you will find $protected $except array
you can add the routes that will not be checked for CSRF Token
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
// for example
"form/route"
];
Create an API endpoint using something like tymondesigns/jwt-auth. You would then request a token first then submit your form to the API endpoint with the token.

Resources