nextauthjs/next-auth · error · TypeError
Missing refresh_token
Error message
Missing refresh_token
What it means
FusionAuth's token refresh logic throws a TypeError when it needs to refresh an expired access_token but the stored token object has no refresh_token property. Without a refresh token there is no way to obtain a new access token, so the provider fails fast. This typically indicates the initial token response did not include a refresh token (or it was not persisted).
Source
Thrown at packages/core/src/providers/fusionauth.ts:181
// the ability to call API's externally that rely on JWT tokens.
callbacks: {
async jwt(params) {
const { token, user, account } = params;
if (account) {
// First-time login, save the `access_token`, its expiry and the `refresh_token`
return {
...token,
...account,
};
} else if (
token.expires_at &&
Date.now() < (token.expires_at as number) * 1000
) {
// Subsequent logins, but the `access_token` is still valid
return token;
} else {
// Subsequent logins, but the `access_token` has expired, try to refresh it
if (!token.refresh_token) throw new TypeError('Missing refresh_token');
try {
const refreshResponse = await fetch(
`${process.env.AUTH_FUSIONAUTH_ISSUER}/oauth2/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: process.env.AUTH_FUSIONAUTH_CLIENT_ID!,
client_secret: process.env.AUTH_FUSIONAUTH_CLIENT_SECRET!,
grant_type: 'refresh_token',
refresh_token: token.refresh_token as string,
}),
}
);
View on GitHub (pinned to a1a16a5a77)
Solutions
- Request the offline access scope in the FusionAuth authorization request so a refresh_token is issued (authorization: { params: { scope: "offline_access" } })
- Verify FusionAuth application settings allow refresh tokens and inspect the initial token response
- Force a full re-login (clear cookies/session) so a fresh token set including refresh_token is obtained
- Audit your adapter/callback code to ensure token.refresh_token is persisted, not stripped
Example fix
// before
import FusionAuth from "@auth/core/providers/fusionauth"
providers: [FusionAuth({ clientId, issuer })] // no offline scope
// after
providers: [
FusionAuth({
clientId: process.env.AUTH_FUSIONAUTH_ID,
clientSecret: process.env.AUTH_FUSIONAUTH_SECRET,
issuer: process.env.AUTH_FUSIONAUTH_ISSUER,
authorization: { params: { scope: "offline_access" } },
})
] Defensive patterns
Strategy: type-guard
Validate before calling
// before relying on refresh, check the stored token
if (!token.refresh_token) {
// force full re-authentication instead of attempting refresh
await clearSession()
} Type guard
function hasRefreshToken(t: { refresh_token?: string | null }): t is { refresh_token: string } {
return typeof t.refresh_token === 'string' && t.refresh_token.length > 0
} Try / catch
try {
await refreshed = refreshAccessToken(token)
} catch (e) {
if (e instanceof TypeError && e.message === 'Missing refresh_token') {
// cannot refresh: invalidate session and redirect user to sign in again
await signOut()
}
} Prevention
- Request the offline_access scope so FusionAuth issues refresh tokens
- Persist token.refresh_token through your adapter/session callbacks (don't strip optional fields)
- Clear cookies and re-login after changing FusionAuth app token settings
- Test the full session-expiry path in staging, not just first login
When it happens
Trigger: On a subsequent login the check Date.now() < token.expires_at * 1000 is false (access token expired), and !token.refresh_token is true — i.e. the persisted token from the initial OAuth callback lacked a refresh_token because the original token request omitted the offline_access scope or the token was stored stripped of the field.
Common situations: Hitting this after a session outlives the access token lifetime; after changing FusionAuth application settings so refresh tokens are no longer issued; or when a custom callback/adapter drops refresh_token when saving tokens (e.g. typed as optional and serialized as undefined).
Related errors
- Failed to refresh token
- Account not created
- Missing or invalid provider account
- Provider not supported
- The account is already associated with another user
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/c30e8e0628ab1570.
Report an issue: GitHub.