How to get cookies server-side in a Next.js app
By Flavio Copes
Learn how to read cookies during server-side rendering in Next.js by forwarding ctx.req.headers.cookie to your Axios request inside getInitialProps for auth.
To read cookies during server-side rendering in Next.js, grab them from ctx.req.headers.cookie inside getInitialProps and forward them to your API request. The server has no other way to see them.
I had this problem. My app depended on cookies for authentication, and using Next.js apparently my cookies were not set on first page initialization.
I had this code, which was in charge of hitting a GET endpoint using Axios:
Bookings.getInitialProps = async ctx => {
const response = await axios.get('http://localhost:3000/api/bookings/list')
return {
bookings: response.data
}
}
I had Passport.js on the server side endpoint, but it failed to authenticate the user on the SSR page, because it didn’t find any cookie.
Why does this happen?
When the page renders on the server, getInitialProps runs in Node.js, not in the browser.
The Axios call above is a server-to-server request. The browser is not involved, so it can’t attach its cookies like it does for normal requests. The API endpoint receives a request with no Cookie header, and Passport.js sees an anonymous user.
The cookies are not lost, though. The browser sent them with the initial page request, so they sit in ctx.req.headers.cookie. We just need to pass them along.
The fix
I had to change my code to this, adding the cookies to the headers:
Bookings.getInitialProps = async ctx => {
const response = await axios({
method: 'get',
url: 'http://localhost:3000/api/bookings/list',
headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined
})
return {
bookings: response.data
}
}
The key to making cookies available in the backend was adding:
headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined
to the Axios configuration.
Why the ternary?
getInitialProps does not only run on the server. When the user navigates to the page from another page of the app, it runs in the browser instead.
In that case ctx.req is undefined, and accessing ctx.req.headers would crash with a TypeError. That’s the pitfall to watch out for: the code works on a full page load, then breaks on client-side navigation.
The ternary handles both cases. On the server we forward the cookie header manually. In the browser we pass undefined, and the browser attaches the cookies itself, as it does for any request to the same origin.
One more thing to check: if the user has no session yet, ctx.req.headers.cookie is undefined too. That’s fine here, Axios skips the header and your endpoint treats the request as unauthenticated, which is what you want.
Related posts about next: