I was reading how server actions can be used to retain sensitive data on the server by never sending such data to the client. I thought this could be useful for retaining access tokens, for instance. I then wrote the code on the client to make calls to server actions to do privileged things. This works fine, with the added caveat that this setup does not work if it is executed during a build step.
I have something like this on the server that uses axios
interceptors to insert the access token into the authorization headers for each request.
axios.interceptors.request.use(async req => {
const session = await getServerSession(authOptions)
req.headers.authorization = `Bearer ${session.access_token}`;
return req;
});
However, getServerSession()
causes issues when compiling routes. That is, when using e.g. npm run build
directly or when making server action calls when using e.g. generateStaticParams
. In either case you see a similar error.
rpm run build
Error: Invariant: headers() expects to have requestAsyncStorage, none available.
at u (/mnt/.next/server/chunks/472.js:30:26016)
at s (/mnt/.next/server/chunks/472.js:30:20315)
at /mnt/.next/server/chunks/881.js:1:10082
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async m (/mnt/.next/server/chunks/881.js:1:9490)
at async Object.x [as generateStaticParams] (/mnt/.next/server/app/posts/[slug]/page.js:1:3453)
at async buildParams (/mnt/node_modules/next/dist/build/utils.js:1025:40)
npm run dev
Error: Invariant: headers() expects to have requestAsyncStorage, none available.
at headers (webpack-internal:///(rsc)/./node_modules/next/dist/client/components/headers.js:38:15)
at getServerSession (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:107:41)
at eval (webpack-internal:///(rsc)/./lib/server.ts:32:86)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async getAllPosts (webpack-internal:///(rsc)/./lib/server.ts:43:9)
at async Object.generateStaticParams (webpack-internal:///(rsc)/./app/posts/[slug]/page.tsx:32:13)
at async buildParams (/mnt/node_modules/next/dist/build/utils.js:1025:40)
✓ Compiled /editor/update/[slug] in 216ms (1737 modules)
My code broadly looks like this:
/app/posts/[slug]/page.tsx
export async function generateStaticParams() {
return (await getAllPosts()).map((slug: string) => ({ slug }))
}
/lib/server.ts
'use server'
axios.interceptors.request.use(async req => {
const session = await getServerSession(authOptions)
req.headers.authorization = `Bearer ${session.access_token}`;
return req;
});
export async function getAllPosts(): Promise<string[]> {
let slugs: string[] = []
await axios.get('/api/slugs/).then((r) => {
slugs = r.data
})
return slugs
}
Any idea what's going on here? Am I doing something overtly incorrect? The flow is:
generateStaticParams (during build)
-> getAllPosts (server)
-> getServerSession (server)
The use of the axios interceptor in the server action does seem to work - it just does not work when called during any sort of compiling step.
Any ideas? What am I doing wrong here? There is of course no “session” during build. Though I was expecting it to return null or some such rather than throw an error. Maybe the answer is to just catch it and do nothing?