Next.js Discord

Discord Forum

Handling Access Token Refresh in Next.js App Router with Server Components

Unanswered
Mainak posted this in #help-forum
Open in Discord
I have a frontend application built using Next.js (App Router), and my backend is a separate Node.js service.

During authentication, my backend generates both an access token and a refresh token. I’m facing a challenge in reliably obtaining a valid access token when the existing one expires.

Here’s what I’ve implemented so far:
• I created a custom Axios instance.
• If an API request fails with a 401 Unauthorized error, I call the refresh-token API.
• The backend returns a new access token, which I then try to store back in cookies.

This flow works fine on the client side.

However, the problem arises when making API calls from Next.js Server Components:
• If a server component makes an API request and receives a 401,
• The Axios interceptor again calls the refresh-token API,
• But the new access token cannot be written back to cookies, because Server Components cannot set cookies.
• Cookies can only be modified inside Server Actions or Route Handlers.

Because of this, even though I successfully get a new access token, it never gets persisted, and subsequent server-side requests continue to fail.

My constraints / requirements:
• I do not want to create proxy route handlers for every API call just to handle token refresh.
• I want a central, scalable, and clean solution.
• I’m open to using middleware or any other recommended pattern, as long as it fits well with the App Router architecture.

So my questions are:
1. What is the best possible way to handle access-token refresh in this scenario?
2. Should this logic live in middleware, or is there a better approach?
3. How can I ensure that refreshed access tokens are properly persisted when the request originates from a Server Component?

Looking for a production-grade recommendation. 🙏

4 Replies

@Mainak I have a frontend application built using Next.js (App Router), and my backend is a separate Node.js service. During authentication, my backend generates both an access token and a refresh token. I’m facing a challenge in reliably obtaining a valid access token when the existing one expires. Here’s what I’ve implemented so far: • I created a custom Axios instance. • If an API request fails with a 401 Unauthorized error, I call the refresh-token API. • The backend returns a new access token, which I then try to store back in cookies. This flow works fine on the client side. However, the problem arises when making API calls from Next.js Server Components: • If a server component makes an API request and receives a 401, • The Axios interceptor again calls the refresh-token API, • But the new access token cannot be written back to cookies, because Server Components cannot set cookies. • Cookies can only be modified inside Server Actions or Route Handlers. Because of this, even though I successfully get a new access token, it never gets persisted, and subsequent server-side requests continue to fail. My constraints / requirements: • I do not want to create proxy route handlers for every API call just to handle token refresh. • I want a central, scalable, and clean solution. • I’m open to using middleware or any other recommended pattern, as long as it fits well with the App Router architecture. So my questions are: 1. What is the best possible way to handle access-token refresh in this scenario? 2. Should this logic live in middleware, or is there a better approach? 3. How can I ensure that refreshed access tokens are properly persisted when the request originates from a Server Component? Looking for a production-grade recommendation. 🙏
Poodle
I think middleware is your answer here. middleware can read and write cookies and runs before your server components even execute. the pattern is check if the access token is expired or close to expiry in middleware, if it is call your refresh endpoint right there, set the new token in cookies, then let the request continue, by the time your server component runs it already has a fresh token. You can decode the jwt in middleware to check the exp claim without verifying the signature since you just need to know if its expired. if its within like 30 seconds of expiry just refresh it proactively. This keeps everything central, no proxy routes needed, works for all server component requests automatically.
Saint Hubert Jura Hound
It would be better for ur backend to handle token refreshes automatically, and keep that logic completely separate from the frontend. Send both the refresh and access token to ur backend, doesnt matter if ur in the browser or nextjs server side, then the backend tried to verify the access token, if it fails it checks the refresh token and generates a new at, sends it back in cookies. If the rt is invalid only then u send the 401. This completely prevents a second call to ur backend in most cases
Australian Freshwater Crocodile
sorry to thread hijack, but does it matter if accesstokens/refreshtokens are stored in a DB or server cookies?
@Australian Freshwater Crocodile sorry to thread hijack, but does it matter if accesstokens/refreshtokens are stored in a DB or server cookies?
Saint Hubert Jura Hound
Whether they are or not is the difference bwtween stateful and stateless auth. Imo statefull auth should be used whenever possible. Storing the rt in a db for example allows you to dynamically update its properties or check validity from anywhere