I get a "419 (unknown status)" error when sending a post
request to login user
POST http://localhost/login 419 (unknown status)
Network request response : "message": "CSRF token mismatch."
Laravel server : http://localhost:80 (XAMPP default port)
Vue server : http://localhost:5173
LoginComponent.vue
<script setup>
import { useRouter } from 'vue-router'
import { useAuthStore } from '../../stores/Auth'
const authUserStore = useAuthStore()
const router = useRouter()
import AuthService from '@/services/AuthService'
import { ref } from 'vue'
const email = ref('')
const password = ref('')
const error = ref('')
const login = async () => {
const payload = {
email: email.value,
password: password.value
}
error.value = null
try {
await AuthService.login(payload)
const authUser = await authUserStore.getAuthUser()
if (authUser) {
authUserStore.setGuest({ value: 'isNotGuest' })
router.push('/')
} else {
const error = Error('Unable to fetch user after login, check your API settings.')
error.name = 'Fetch User'
throw error
}
} catch (error) {
error.value = getError(error)
}
}
</script>
<template>
<form @submit.prevent="login">
<div>
<label>Email address</label>
<input v-model="email" />
</div>
<div>
<label>Password</label>
<inpu v-model="password" />
</div>
<button type="submit">Sign in</button>
</form>
</template>
services/AuthService.js
export const authClient = axios.create({
baseURL: 'http://localhost:80',
withCredentials: true // required to handle the CSRF token
})
/*
* Add a response interceptor
*/
authClient.interceptors.response.use(
(response) => {
return response
},
function (error) {
const authUserStore = useAuthStore()
if (error.response && (error.response.status === 401 || error.response.status === 419)) {
authUserStore.logout()
}
return Promise.reject(error)
}
)
export default {
async login(payload) {
await authClient.get('/sanctum/csrf-cookie')
await authClient.post('/login', payload)
},
}
stores/Auth.js
import { defineStore } from 'pinia'
import AuthService from '@/services/AuthService'
export const useAuthStore = defineStore('auth', {
state: () => ({ user: null, loading: false, error: null }),
getters: {
guest: () => {
const storageItem = window.localStorage.getItem('guest')
if (!storageItem) return false
if (storageItem === 'isGuest') return true
if (storageItem === 'isNotGuest') return false
}
},
actions: {
SET_USER(state, user) {
state.user = user
},
async getAuthUser() {
this.SET_LOADING(true)
try {
const response = await AuthService.getAuthUser()
this.SET_USER(response.data.data)
return response.data.data
} catch (error) {
this.SET_USER(null)
}
},
setGuest({ value }) {
window.localStorage.setItem('guest', value)
},
}
})
env variables
SESSION_DRIVER=cookie
SANCTUM_STATEFUL_DOMAINS=http://localhost:5173
SPA_URL=http://localhost:5173
SESSION_DOMAIN=localhost
cors.php
'paths' => [
'api/*',
'login',
'sanctum/csrf-cookie',
...
],
'allowed_origins' => [env('SPA_URL','http://localhost:5173')],
fortify.php
'home' => env('SPA_URL') . '/',
'views' => false,
'features' => [
Features::registration(),
],
sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
],
bootstrap.js
import axios from "axios";
window.axios = axios;
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
window.axios.defaults.withCredentials = true;
window.axios.defaults.withXSRFToken = true;
It appeared that axios
doesn't send CSRF-TOKEN
in the login request headers
by deafault, So i had to grap the cookie initiated from the request to sanctum/csrf-cookie
, and then send it manually with the request headers
to /login
route:
function getCookie(name) {
const value = document.cookie
const parts = value.split(name)
if (parts.length === 2) {
return parts.pop().split(';').shift()
}
}
const login = () => {
axios.get('http://localhost:80/sanctum/csrf-cookie', {
withCredentials: true
})
const csrfToken = getCookie('XSRF-TOKEN=')
const payload = {
email: email.value,
password: password.value
}
axios.post('http://localhost/login', payload, {
headers: {
'X-XSRF-TOKEN': decodeURIComponent(csrfToken)
},
withCredentials: true
})
}