immich-app/immich · error · BadRequestException

Received backchannel logout request but OAuth is not enabled

Error message

Received backchannel logout request but OAuth is not enabled

What it means

backchannelLogout handles OIDC Back-Channel Logout requests from the identity provider. It first requires that OAuth is enabled in the server config; if oauth.enabled is false, the request is rejected with this BadRequestException (400) because there is no OAuth session machinery to process a logout for.

Solutions

  1. Remove the Backchannel Logout URL from the OAuth client configuration in your identity provider, or point it at the correct Immich instance.
  2. Re-enable OAuth (Administration > Settings > Authentication > OAuth) if the IdP logout notifications are expected.
  3. Ignore/skip 400s for this endpoint in the IdP logs if OAuth is intentionally disabled.
  4. Sync Immich's oauth.enabled setting with the IdP client registration lifecycle.

Example fix

// before: IdP sends logout to a server with oauth disabled -> 400
// after (Keycloak admin): remove the Backchannel Logout URL
// Client > Advanced > Backchannel Logout URL: <empty> (OAuth disabled in Immich)
Defensive patterns

Strategy: try-catch

Validate before calling

// IdP-side: only register the backchannel logout URL when Immich has oauth.enabled=true
const cfg = await api.getServerConfig();
console.assert(cfg.oauthEnabled, 'Immich OAuth disabled; do not register backchannel logout URL');

Try / catch

try { await idp.registerBackchannel(immichUrl); } catch (e) { logWarnOnce('Immich rejected backchannel logout; OAuth disabled'); }

Prevention

When it happens

Trigger: The IdP posts a backchannel-logout request (with logout_token) to /api/oauth/backchannel-logout while the Immich server config has oauth.enabled === false — i.e. OAuth was disabled after the IdP was configured to send logout notifications.

Common situations: Admin disabling OAuth in Immich but forgetting to remove the back-channel logout URL in Keycloak/Auth0/Okta; IdP sending logout broadcasts to all registered clients after OAuth was toggled off; misconfigured instance pointing at the wrong server.

Related errors


AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15). Data as JSON: /api/errors/693b95ca92d96781. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/auth.service.ts:97

  async logout(auth: AuthDto, authType: AuthType): Promise<LogoutResponseDto> {
    let oauthBearerToken: string | undefined;
    if (auth.session) {
      const session = await this.sessionRepository.get(auth.session.id);
      oauthBearerToken = session?.oauthBearerToken ?? undefined;
      await this.sessionRepository.delete(auth.session.id);
      await this.eventRepository.emit('SessionDelete', { sessionId: auth.session.id });
    }

    return {
      successful: true,
      redirectUri: await this.getLogoutEndpoint(authType, oauthBearerToken),
    };
  }

  async backchannelLogout(dto: OAuthBackchannelLogoutDto): Promise<void> {
    const { oauth } = await this.getConfig({ withCache: false });
    if (!oauth.enabled) {
      throw new BadRequestException('Received backchannel logout request but OAuth is not enabled');
    }

    let claims;
    try {
      claims = await this.oauthRepository.validateLogoutToken(oauth, dto.logout_token);
    } catch (error: Error | any) {
      this.logger.error(`Error backchannel logout: ${error.message}`);
      this.logger.error(error);

      throw new BadRequestException('Error backchannel logout: token validation failed');
    }

    if (!claims) {
      throw new BadRequestException('Invalid logout token: no claims found');
    }

    if (!claims.sub && !claims.sid) {
      throw new BadRequestException('Invalid logout token: it must contain either a sub or a sid claim');

View on GitHub (pinned to f48d4b3321)