Replies: 3 comments 1 reply
|
I have the same requirement. I was thinking of manually calling the jwt callback by retrieving the options. |
|
I have the same problem and I think there is no solution to this at the moment which is frustrating. The only workaround I think is to add a refresh token logic in the api yourself. Basically, call that refreshToken function manually if API route returns 401 and you still have a refreshToken. If you use getServerSession function instead of getToken function, it runs your jwt callback everytime you call the session. So it solves the problem but you have to expose the accessToken in the session this way which is a security issue itself. Is there any plan to fix this at all or if there is a solution I would like to hear about it. |
|
It reads/decrypts the JWT from the cookie, but it does not run the full session/JWT callback pipeline the way What tends to work better:
So the short version is: |
|
This is a known limitation: Why it works this wayThe JWT callback runs during the sign-in flow and during Solution 1 — Implement refresh inside the API route (recommended)Check expiry manually and refresh when needed: // pages/api/proxy.ts (or app/api/proxy/route.ts)
import { getToken } from 'next-auth/jwt';
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const token = await getToken({ req });
if (!token) return res.status(401).json({ error: 'Unauthenticated' });
// Check if access token is expired
const isExpired = Date.now() > (token.accessTokenExpires as number);
if (isExpired) {
// Call your token refresh endpoint directly
const refreshed = await refreshAccessToken(token.refreshToken as string);
if (!refreshed) return res.status(401).json({ error: 'Session expired' });
// Use the new access token for this request
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${refreshed.accessToken}` },
});
return res.json(await response.json());
}
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${token.accessToken}` },
});
return res.json(await response.json());
}
async function refreshAccessToken(refreshToken: string) {
try {
const res = await fetch('https://oauth-provider.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: process.env.CLIENT_ID!,
client_secret: process.env.CLIENT_SECRET!,
}),
});
return res.ok ? await res.json() : null;
} catch {
return null;
}
}Solution 2 — Use
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hello everyone,
First, I have a catch-all proxy in
pages/api/proxy/[...all].tsthe purpose of this is to attach the access token to theAuthorization: Bearer ${accessToken}header for all our api calls.To do this I have to get the token inside this proxy and attach it using
const token = await getToken({ req, secret })I have the Refresh token rotation implemented and working fine. Now the problem is: when this token is expired the
getToken()is not waiting for it to renew or in simpler words it is not checking theJWT callbackwhich inside we check the token expiration. So it results in401error where thegetToken()is still using the old token.How do I solve this when the first thing that user hits when they enter the page is the
getToken()?All reactions