Intro
I’m new to development and it’s more of a hobby for me. As part of my personal project, I faced a simple task: client-server interaction between a NestJS server and Next.js client. Following the latest requirements, I implemented authorization through a pair of tokens with different lifetime and storing them in the client’s browser cookie. And this is where the adventure began.
Problem
Next.js imposes very strict restrictions on working with cookies, so you can’t just write new tokens received. This must happen in Server Actions or Route Handlers. You can also do it in middleware. The Internet is full of instructions on how to bypass these restrictions using Axios, third-party libraries for working with cookies, wrapping requests to an external server in Route Handlers, etc.
I tried them all, and none of them worked well.
In addition, I strongly dislike the idea of putting something in the system to replace existing tools because I couldn’t figure them out. The Next.js developers designed it with fetch() in mind as a tool for executing queries, deliberately put restrictions on working with cookies, created Server Actions and Route Handlers for purposes unrelated to third-party APIs.
Thus, the question arises: how to implement the process of updating tokens with storage in browser cookies using built-in Next.js tools?
Current state
Thanks to the person who created the FAQ for the Next.js Discord Server, he gave me an idea and I was able to get some results. Currently implemented:
- Retrieving tokens from the server and saving to cookies
- Controlling through middleware the state of the cookie and updating it if necessary.
And everything seems to work, but there is a problem: the corner case when a page was loaded with a valid token, and then (say, right after the load is complete) the token expires.
On the next request (navigating to another page, for example), the app behaves unpredictably, using the cache almost randomly.
To demonstrate the problem, I created two public repositories and placed them on free hosting:
- API server with NestJS
- Client application with Next.js 14
- GitHub
- Deployed on Vercel
- Key files: wrapper around fetch() and middleware
Token lifetimes are intentionally set very short: 30 seconds and 3 minutes. You can check for yourself how weird it looks when AccessToken has already expired, middleware has already updated both tokens, and the application is still running with cache.
Something like revalidatePath('/', 'layout')
would be very useful here, but this is impossible in middleware.
Question for the community
Is there any way to update tokens in cookies without losing the consistency of the global state of the application, and without using third-party libraries or dirty hacks?