Question
Is there a way to pass Laravel csrf token to Vue given that the Laravel backend and the Vue frontend are separated from each other (in diferent directory and in diferent subdomains) ??
I'm building an application and would like to have separated backend and frontend for organization purposes and for because it facilitates team work. So, it would be something like:
- api.mydomainexample.com (Laravel backend)
- mydomainexample.com (Vue frontend for public)
- admin.mydomainexample.com (Vue Frontend for admin only)
Is this possible? What I thought was maybe running a nodejs server for the frontend project and make the nodejs server communicate with the laravel server. Don't know how to do that.
I found [similiar stackoverflow questions](https://stackoverflow.com/questions/50325287/pass-csrf-token-from- laravel-to-vue), but the responses from them do not solve my problem. The best thing I found was [this](http://%20https://stackoverflow.com/questions/59389557/how-to-pass-a- csrf-token-safely-to-a-separate-vuejs-frontend), which proposes to use Laravel passport. But, is the proposal the only one that works? If so, does Laravel passport protect users from CSRF attacks?
Actually, if there is an workaround which enables to have separated backend and frontend while protecting against CSRF tokens, then that would be perfect!
Answer
Use Sanctum
LARAVEL BACKEND
- Install Sanctum via Composer
composer require laravel/sanctum
- Publish the Sanctum configuration and migration files
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
- Run your migrations - Sanctum will add a table to store API tokens
php artisan migrate
- Add Sanctum's middleware to your api middleware group in your
App/Http/Kernel.php
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
- Configure which domains your SPA will be making requests from. From the docs:
You may configure these domains using the stateful configuration option in your sanctum configuration file. This configuration setting determines which domains will maintain "stateful" authentication using Laravel session cookies when making requests to your API.
So - Update your config\sanctum.php
to include something like this:
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1')),
- Configure your
config/cors.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', '*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
- Configure your
config/session.php
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set.
|
*/
'domain' => env('SESSION_DOMAIN', null),
- In your
.env
, add the following:
// Change .your-site.local to whatever domain you are using
// Please note the leading '.'
SESSION_DOMAIN=.your-site.local
SANCTUM_STATEFUL_DOMAINS=your-site.local:8000
CORS_ALLOWED_ORIGINS=http://app.your-site.local:8000
- Run a
php artisan config:clear
VUE FRONTEND
- In your front-end, create the following folder/file structure
@/src/services/api.js
api.js :
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL,
withCredentials: true,
});
export default apiClient;
In the root directory, place an .env file with the following in it:
VUE_APP_API_URL= 'http://api.your-site.local'
- To authenticate, your SPA should first make a request to the
/sanctum/csrf-cookie
. This sets theXSRF-TOKEN
cookie. This token needs to be sent on subsequent requests ( axios will handle this for you automatically ). Immediately after, you'll want to send aPOST
request to your Laravel/login
route.
On your Vue front-end login component:
import Vue from 'vue'
import apiClient from '../services/api';
export default {
data() {
return {
email: null,
password: null,
loading: false,
};
},
methods: {
async login() {
this.loading = true; // can use this to triggle a :disabled on login button
this.errors = null;
try {
await apiClient.get('/sanctum/csrf-cookie');
await apiClient.post('/login', {
email: this.email,
password: this.password
});
// Do something amazing
} catch (error) {
this.errors = error.response && error.response.data.errors;
}
this.loading = false;
},
},