Can't having Usefetch working with Session/Cookies on SERVER SIDE ONLY (using laravel sanctum api)

Hello How can I have usefetch working perfectly with Session/Cookies on SERVER SIDE ONLY using laravel sanctum api. It works perfectly if my middleware is client side (if process.client) but doesn't work anymore if my middleware if server side only (process.server) If i'm using nuxt server side only Laravel is returning me this : CSRF token mismatch. Here my middleware
export default defineNuxtRouteMiddleware(async (to, from) => {
// skip middleware on client
if (process.client) return

const code = to.query.code as string

if (!code) {
return navigateTo('/')
}

const auth = useAuthStore()

if (auth.isLoggedIn) {
return navigateTo('/')
}

await useSanctumFetch('/sanctum/csrf-cookie')

const { data, error } = await useSanctumFetch('/login/discord', {
method: 'POST',
params: {
code: code,
},
})

const auth = useAuthStore()
if (data.value) auth.user = data.value.user as User

return navigateTo('/')
})
export default defineNuxtRouteMiddleware(async (to, from) => {
// skip middleware on client
if (process.client) return

const code = to.query.code as string

if (!code) {
return navigateTo('/')
}

const auth = useAuthStore()

if (auth.isLoggedIn) {
return navigateTo('/')
}

await useSanctumFetch('/sanctum/csrf-cookie')

const { data, error } = await useSanctumFetch('/login/discord', {
method: 'POST',
params: {
code: code,
},
})

const auth = useAuthStore()
if (data.value) auth.user = data.value.user as User

return navigateTo('/')
})
15 Replies
! GhostvOne.tv 👻🇫🇷
useSanctumFetch.ts
import type { UseFetchOptions } from '#app'
import { defu } from 'defu'

export const useSanctumFetch = <T>(
url: string | (() => string),
options?: UseFetchOptions<T>
) => {
const auth = useAuthStore()
const config = useRuntimeConfig().public

function getCookie(name, data) {
const value = `; ${data}`
const parts = value.split(`; ${name}=`)
if (parts.length === 2) return parts.pop().split(';').shift()
}

let headers = {
...(auth.csrfToken && {
'X-XSRF-TOKEN': decodeURIComponent(auth.csrfToken),
}),
...{
Accept: 'application/json',
'Content-Type': 'application/json',
I tried this bellow
// referer: config.appUrl,
},
}

if (process.server) {
headers = {
...headers,
...useRequestHeaders(['referer', 'cookie']),
referer: config.appUrl,
}
}

const defaults: UseFetchOptions<T> = {
baseURL: config.apiUrl,
credentials: 'include',
key: typeof url === 'string' ? url : url(),
watch: false,
headers: headers,
onResponse: (response) => {
if (process.server) {
auth.csrfToken = getCookie(
'XSRF-TOKEN',
response.response.headers.get('set-cookie') ?? ''
)
}

if (process.client) {
auth.csrfToken = useCookie('XSRF-TOKEN').value
}
},
}

const params = defu(options, defaults)
console.log(params)

return useFetch(url, params)
}
import type { UseFetchOptions } from '#app'
import { defu } from 'defu'

export const useSanctumFetch = <T>(
url: string | (() => string),
options?: UseFetchOptions<T>
) => {
const auth = useAuthStore()
const config = useRuntimeConfig().public

function getCookie(name, data) {
const value = `; ${data}`
const parts = value.split(`; ${name}=`)
if (parts.length === 2) return parts.pop().split(';').shift()
}

let headers = {
...(auth.csrfToken && {
'X-XSRF-TOKEN': decodeURIComponent(auth.csrfToken),
}),
...{
Accept: 'application/json',
'Content-Type': 'application/json',
I tried this bellow
// referer: config.appUrl,
},
}

if (process.server) {
headers = {
...headers,
...useRequestHeaders(['referer', 'cookie']),
referer: config.appUrl,
}
}

const defaults: UseFetchOptions<T> = {
baseURL: config.apiUrl,
credentials: 'include',
key: typeof url === 'string' ? url : url(),
watch: false,
headers: headers,
onResponse: (response) => {
if (process.server) {
auth.csrfToken = getCookie(
'XSRF-TOKEN',
response.response.headers.get('set-cookie') ?? ''
)
}

if (process.client) {
auth.csrfToken = useCookie('XSRF-TOKEN').value
}
},
}

const params = defu(options, defaults)
console.log(params)

return useFetch(url, params)
}
Nuxt .env
APP_URL=http://localhost:3000
API_URL=http://localhost:8000
APP_URL=http://localhost:3000
API_URL=http://localhost:8000
nuxt.config.ts
export default defineNuxtConfig({
css: ['~/assets/css/app.css'],
devtools: { enabled: true },
modules: ['@nuxtjs/tailwindcss', '@pinia/nuxt'],
runtimeConfig: {
public: {
appUrl: process.env.APP_URL,
apiUrl: process.env.API_URL,
},
},
})`
export default defineNuxtConfig({
css: ['~/assets/css/app.css'],
devtools: { enabled: true },
modules: ['@nuxtjs/tailwindcss', '@pinia/nuxt'],
runtimeConfig: {
public: {
appUrl: process.env.APP_URL,
apiUrl: process.env.API_URL,
},
},
})`
On my laravel .env I have :
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:3000
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:3000
cors.php (into laravel sanctum)
<?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/*', 'login/discord', 'sanctum/csrf-cookie'],
'paths' => ['*'],

'allowed_methods' => ['*'],

'allowed_origins' => ['*'],

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => true,

];
<?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/*', 'login/discord', 'sanctum/csrf-cookie'],
'paths' => ['*'],

'allowed_methods' => ['*'],

'allowed_origins' => ['*'],

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => true,

];
What's wrong ? Why if i'm server side with nuxt it doesn't work anymore ? I tried everything since multiple days but can't fix that.
Sibyl
Sibyl13mo ago
so on server side you probably don't get the cookie that's probably what's causing the issue you can put your tokens on the pinia store and persist it pinia will share those tokens using cookies between client and the server might help
! GhostvOne.tv 👻🇫🇷
That is what I'm doing but it doesn't work. I don't know why..... it's like sanctum laravel api doesn't accept my server request I have a cookie; but didn't match when i call back my api and on the client side, works perfectly
Sibyl
Sibyl13mo ago
the cookie is set when making request to /sanctum/csrf-cookie?
! GhostvOne.tv 👻🇫🇷
Yes right
Sibyl
Sibyl13mo ago
I'm not sure but can you use useAsyncData there? it might be used only inside script setup but i'm not sure
! GhostvOne.tv 👻🇫🇷
I could but never used that I don't know how to do that atm I can try
Sibyl
Sibyl13mo ago
useAsyncData shared the result between client & server so it might work
! GhostvOne.tv 👻🇫🇷
not usefetch ?
Sibyl
Sibyl13mo ago
usefetch uses useAsyncData under the hood
! GhostvOne.tv 👻🇫🇷
So usefetch should work ?
Sibyl
Sibyl13mo ago
yeah
! GhostvOne.tv 👻🇫🇷
didnt work with useAsyncData Laravel use TOKEN + session cookie and I don't know how to get these cookies from my server side. it's like session cookie doesnt exist on my nuxt server side
! GhostvOne.tv 👻🇫🇷
same issue as him atm
No description
Titseas
Titseas2d ago
did you manage to find a solution here?
Want results from more Discord servers?
Add your server