immich-app/immich · error
Error validating JWT logout token
Error message
Error validating JWT logout token
What it means
validateLogoutToken verifies a back-channel logout JWT (signature, issuer, audience, expiry) and rethrows any verification failure as 'Error validating JWT logout token' with the original error as cause. It means the logout token received from the OIDC provider could not be trusted and the logout event is rejected.
Solutions
- Inspect the logged underlying error message (`Error validating JWT logout token: <reason>`) for the specific verify failure
- Verify the issuer URL and audience config match the provider exactly
- Clear/refresh JWKS cache after provider key rotation
- Confirm the provider is sending a proper logout token (with `events` claim) rather than a regular token
Example fix
// before // issuerUrl: 'https://provider.example.com' // after // issuerUrl: 'https://provider.example.com/' // must match the iss claim exactly (trailing slash)
Defensive patterns
Strategy: try-catch
Validate before calling
// decode without verification first to inspect claims
const { payload } = jwtDecode(logoutToken);
if (!payload?.iss || payload.iss !== expectedIssuer) console.warn('Logout token issuer mismatch', payload?.iss); Type guard
const isLogoutToken = (p: any): p is { events: object; sid?: string; sub?: string } =>
p && typeof p === 'object' && 'events' in p && Object.keys(p.events).some(k => k.includes('backchannel-logout')); Try / catch
try {
await oauthRepo.validateLogoutToken(token);
} catch (e) {
logger.error('Back-channel logout token rejected', { reason: (e as any).cause?.message });
return res.status(400).send(); // per OIDC back-channel logout spec
} Prevention
- Monitor the cause message — it names the exact verify failure (expired, sig, iss, aud)
- Refresh JWKS promptly after provider key rotation
- NTP-synchronize the server to avoid clock-skew exp/nbf failures
- Confirm with the provider that back-channel logout is enabled and sends proper logout tokens
When it happens
Trigger: A back-channel logout POST delivers a JWT that fails jwtVerify: bad/expired signature, wrong issuer or audience, expired token, missing claims (events/sid/sub), or malformed token format.
Common situations: JWKS rotated and the old key is cached; provider issuer URL misconfigured in the app; clock skew marking the token invalid; provider sends an unexpected token type (e.g. access token instead of logout token).
Related errors
- Error backchannel logout: token validation failed
- Invalid logout token: no claims found
- Invalid logout token: it must contain either a sub or a sid…
- Received backchannel logout request but OAuth is not enabled
- Error in OAuth discovery
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/29b7eca421326c24.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/repositories/oauth.repository.ts:191
// eslint-disable-next-line unicorn/prefer-https
if (!events || !events['http://schemas.openid.net/event/backchannel-logout']) {
throw new Error('Missing backchannel-logout event claim');
}
// "nonce" must not be present
if (payload.nonce) {
throw new Error('Logout token must not contain a nonce');
}
return {
sub: payload.sub,
sid: payload.sid as string | undefined,
};
} catch (error: Error | any) {
this.logger.error(`Error validating JWT logout token: ${error.message}`);
this.logger.error(error);
throw new Error('Error validating JWT logout token', { cause: error });
}
}
private async getClient({
issuerUrl,
clientId,
clientSecret,
profileSigningAlgorithm,
signingAlgorithm,
tokenEndpointAuthMethod,
timeout,
allowInsecureRequests,
}: OAuthConfig) {
try {
return await discovery(
new URL(issuerUrl),
clientId,
{View on GitHub (pinned to e55ac299a4)