payloadcms/payload · error · Error
Cannot refresh token: user not authenticated
Error message
Cannot refresh token: user not authenticated
What it means
The `refresh` server function calls `payload.auth({ headers })`; if the returned `result.user` is null/undefined it throws this. There is no authenticated session to refresh: the request carried no valid (or already expired/destroyed) auth token.
Source
Thrown at packages/payload/src/auth/serverFunctions/refresh.ts:30
config: MaybePromise<SanitizedConfig>
serverAdapter: ServerAdapter
}
/**
* Refreshes the current user's auth token and rewrites the cookie through the
* supplied `serverAdapter`, so the function is framework-agnostic; each adapter
* binds its own.
*/
export async function refresh({
config,
serverAdapter,
}: RefreshArgs): Promise<{ message: string; success: boolean }> {
const payload = await getPayload({ config, cron: true })
const headers = await serverAdapter.getHeaders()
const result = await payload.auth({ headers })
if (!result.user) {
throw new Error('Cannot refresh token: user not authenticated')
}
const existingCookie = await getExistingAuthToken({
cookiePrefix: payload.config.cookiePrefix,
serverAdapter,
})
if (!existingCookie) {
return { message: 'No valid token found to refresh', success: false }
}
const collection: CollectionSlug | undefined = result.user.collection
const collectionConfig = payload.collections[collection]
if (!collectionConfig?.config.auth) {
throw new Error(`No auth config found for collection: ${collection}`)
}
View on GitHub (pinned to 00c58b35c0)
Solutions
- Guard the `refresh` call behind a session/cookie presence check.
- Verify `serverAdapter.getHeaders()` forwards the auth cookie.
- If the token expired, call `login` first to obtain a fresh token before refreshing.
Example fix
// before
await refresh({ config, serverAdapter })
// after
const authed = await payload.auth({ headers: await serverAdapter.getHeaders() })
if (!authed.user) {
await login({ collection: 'users', config, email, password, serverAdapter })
} else {
await refresh({ config, serverAdapter })
} Defensive patterns
Strategy: validation
Validate before calling
async function hasSessionCookie(serverAdapter) {
const headers = await serverAdapter.getHeaders()
const cookie = headers.get('cookie') ?? ''
return /payload-token=/.test(cookie)
}
// before refresh:
if (!(await hasSessionCookie(serverAdapter))) await redirectToLogin() Type guard
function isAuthenticated(authResult): authResult is { user: Record<string, unknown> } {
return !!authResult?.user
} Try / catch
try {
await refresh({ config, serverAdapter })
} catch (e) {
if (e instanceof Error && /not authenticated/.test(e.message)) {
await redirectToLogin()
} else {
throw e
}
} Prevention
- Guard refresh calls behind a session/cookie check.
- Forward cookies through SSR adapters.
- Treat refresh failure as a re-login trigger, not a crash.
When it happens
Trigger: Calling `refresh({ config, serverAdapter })` when `serverAdapter.getHeaders()` returns headers with no `payload-token` cookie, an expired token, or a token whose user/session was deleted. The auth lookup resolves to no user.
Common situations: Token expired and the client did not re-login; an SSR adapter stripped the cookie; the user was deactivated/deleted; refresh invoked on an already-logged-out session.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- No auth config found for collection: ${collection}
- No User
- error:notAllowedToPerformAction
- Token is either invalid or has expired.
- Verification token is invalid.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/47de5786abb18eb3.
Report an issue: GitHub.