Had to open that project to check it out.
I have these routes related to authentication
GET /auth/me - returns current user data
GET /auth/session - returns the session token
POST /auth/login - logs the user in
POST /auth/logout - logs the user out (destroy session)
All these routes are on the web middleware stack, so responds with cookies.
I have an helper file with this axios config
// libs/http-client.js
import axios from 'axios';
let csrfToken = null;
const httpClient = axios.create();
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.interceptors.request.use(function (config) {
if (csrfToken) {
config.headers['X-CSRF-TOKEN'] = csrfToken;
}
return config;
});
axios.interceptors.response.use(function (response) {
if (status === 419) {
httpClient.get('/auth/session');
}
if (response.data && response.data.csrf_token) {
csrfToken = response.data.csrf_token;
}
return response;
});
export default httpClient;
When the app is created I send a request to /auth/session so the token is retrieved and saved locally and then a request to /auth/me to retrieve the current user. (in Nuxt.js I do this on the 'store/index.jsinside thenuxtServerInit` action, I don't know where to do in Next, but I am sure there is somewhere to do initialization there).
In every component that I need to send a request ajax request I import the axios instance like this (using Vue here):
import httpClient from '@/libs/http-client.js'; // where you saved the file above
export default {
// ...
methods: {
submit() {
httpClient.post(...);
},
},
}
So I always use the axios instance created with those interceptors.
If you don't want to use axios you could export a factory function to always create a XHR or fetch instance with the required headers.
The trick is that after login and logout the CSRF token is regenerated by Laravel. The solution is to redirect to /auth/session after logging in or logging out with status code 303 so the redirect is done automatically by axios/XHR/fetch with the GET method.
As the interceptor will check if the response contains a csrf_token key it will update the token locally correctly.
For reference this are the details on the Laravel side
- SessionTokenController
namespace App\Http\Controllers\Auth;
use App\Http\Requests\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Response;
class SessionTokenController extends Controller
{
public function show(Request $request)
{
$csrfToken = $request->session()->token();
return Response::json(['csrf_token' => $csrfToken]);
}
}
2.To redirect after login, override the authenticated method in the LoginController
protected function authenticated(Request $request, $user)
{
return Redirect::to('/auth/session', 303);
}
3.To redirect after logout, override the loggedOut method in the LoginController
protected function loggedOut(Request $request)
{
return Redirect::to('/auth/session', 303);
}
This way after logging in and logging out the SPA CSRF token will be synced with the refreshed token from the Laravel session.
Last tip: increase the session expiration. As most of the time your SPA will interact with Laravel through the API stack the session token will not be renewed when it expires. So it is a good idea to increase the default session expiration time to avoid dropped API calls.