Fastest way to get Laravel SPA authentication up and running
The goal of this post is not to explain what/how/why things work but to skip all the fluff and get your Laravel SPA authentication up and running in no time.
I plan to publish a more in-depth post and a video on this topic, so be sure to keep an eye on this blog, subscribe to my YT channel, and follow me on twitter.
Let's goooowww.
Laravel quick setup
- Create a new Laravel application
laravel new api
cd
into your new application and installlaravel/breeze
cd api
composer require laravel/breeze
- Scaffold authentication API using Laravel Breeze
php artisan breeze:install api
- Open
.env
and:
- set
FRONTEND_URL
to the url of your SPA. This is usuallyhttp://localhost:5173
for a VueJS app using Vite. - set
SANCTUM_STATEFUL_DOMAINS
to the url of your SPA but without the http protocol. - update your database connection details.
FRONTEND_URL=http://localhost:5173
SANCTUM_STATEFUL_DOMAINS=localhost:5173
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=api
DB_USERNAME=root
DB_PASSWORD=yourRootPassword
Make sure the frontend url and stateful domain don't contain a trailing slash /
.
In our example, it's http://localhost:5173
not http://localhost:5173/
, and localhost:5173
not localhost:5173/
.
- Open
database/DatabaseSeeder.php
and seed a test user:
\App\Models\User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
- Start your Laravel application.
php artisan serve
Usually, Laravel will run at http://127.0.0.1:8000
, but you can also access it at http://localhost:8000
.
Because the Laravel API and Frontend App must run on the same top-level domain, we'll use the second url (localhost) when performing our frontend HTTP requests.
We are done configuring Laravel!
Frontend instructions
We'll use the axios library to perform HTTP requests. Axios is a more user-friendly alternative and does some good things out of the box (like automatically sending the csrf cookie as X-XSRF-TOKEN
header).
Make sure you configure axios to include credentials (cookies) with every request. Then, before you attempt to authenticate or register an account, request a csrf token by making an initial GET request to http://localhost:8000/sanctum/csrf-cookie
.
// configure axios to include credentials
axios.defaults.withCredentials = true;
// ask for csrf cookie
axios.get('http://localhost:8000/sanctum/csrf-cookie')
.then(() => {
// attempt to authenticate
axios.post('http://localhost:8000/login', {
email: form.value.email,
password: form.value.password,
}).then(() => {
// user is authenticated
});
});
Once the authentication is successful, every subsequent request you make will be treated as an "authenticated request". For example, you can make a request to get the current user details (the endpoint is included by default in routes/api.php
).
axios.get(`http://localhost:8000/api/user`)
.then((response) => {
console.log(response.data); // outputs user details
});
However, the session will expire at some point due to user inactivity. When that happens, you will get back a 419
or 401
response code, in which case you need to redirect the user to the login page.
When using axios, you could set up a response interceptor like the one bellow:
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
if (error.request.status === 403) {
// redirect to a 403 page informing
// the action is forbidden
router.push('/403');
}
if ([401, 419].includes(error.request.status)) {
// redirect to login
router.push('/login');
}
return Promise.reject(error);
});
And that was it. Your Laravel SPA authentication should be up and running. If it's not, and things didn't work out as expected, subscribe and wait for the in-depth video or hit me up on twitter. Bye!