I have a Nextjs 13 frontend (app router) that communicates with a Laravel-powered backend via api. For authentication in the api, I'm using Laravel Sanctum (as recommended by Laravel for SPAs): basically, authentication works by setting two cookies (a session and a CSRF token) after login, which should then be attached to all future requests, along with a X-Xsrf-Token
header that passes the CSRF token.
To send a request from a client component, I can do:
import cookies from 'js-cookie'
fetch( [url], {
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Origin": [origin],
"X-Requested-With": "XMLHttpRequest",
"X-Xsrf-Token": cookies.get( "XSRF-TOKEN" ),
// Since we're on the browser, cookies are automatically attached via the 'Cookie' header
},
credentials: 'include'
})
If I send a request from a server component, I can do:
import { cookies, headers } from "next/headers"
fetch( [url], {
headers: {
"Cookie": cookies().toString(), // Must attach cookies manually
"Referer": headers().get( "referer" ) ?? "",
"X-Xsrf-Token": cookies().get( "XSRF-TOKEN" ).value,
},
})
Both fetchers work. However, sometimes I need to make the same request both from a server component and from a client component, so I would like to use a single fetcher like this (this is a quick and dirty example just to get my point across):
import cookies from 'js-cookie'
import { cookies, headers } from "next/headers"
fetch( [url],
isServer
?
{
headers: {
"Cookie": cookies().toString(), // Must attach cookies manually
"Referer": headers().get( "referer" ) ?? "",
"X-Xsrf-Token": cookies().get( "XSRF-TOKEN" ).value,
}
}
:
{
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Origin": process.env.NEXT_PUBLIC_APP_URL,
"X-Requested-With": "XMLHttpRequest",
"X-Xsrf-Token": cookies.get( "XSRF-TOKEN" ),
// Since we're on the browser, cookies are automatically attached via the 'Cookie' header
},
credentials: 'include'
}
)
But this throws an error in client components because the cookies()
and headers()
functions can only be used in server components.
So, in short, how can I write a single fetcher that works both on server and client components?