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

  1. Inspect the logged underlying error message (`Error validating JWT logout token: <reason>`) for the specific verify failure
  2. Verify the issuer URL and audience config match the provider exactly
  3. Clear/refresh JWKS cache after provider key rotation
  4. 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

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


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)