immich-app/immich · warning · BadRequestException

OAuth is not enabled

Error message

OAuth is not enabled

What it means

BadRequestException (HTTP 400) thrown by AuthService.authorize when system config `oauth.enabled` is false. The authorize endpoint (POST /oauth/authorize) is the OAuth entry point; calling it without enabling OAuth in Administration > Settings returns this. Config is re-read without cache so a recent admin toggle is honored immediately.

Source

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

      return this.validateSession(session, headers);
    }

    if (apiKey) {
      return this.validateApiKey(apiKey);
    }

    throw new UnauthorizedException('Authentication required');
  }

  getMobileRedirect(url: string) {
    return `${MOBILE_REDIRECT}?${url.split('?', 2)[1] || ''}`;
  }

  async authorize(dto: OAuthConfigDto) {
    const { oauth } = await this.getConfig({ withCache: false });

    if (!oauth.enabled) {
      throw new BadRequestException('OAuth is not enabled');
    }

    return await this.oauthRepository.authorize(
      oauth,
      this.resolveRedirectUri(oauth, dto.redirectUri),
      dto.state,
      dto.codeChallenge,
    );
  }

  async callback(dto: OAuthCallbackDto, headers: IncomingHttpHeaders, loginDetails: LoginDetails) {
    const { oauth } = await this.getConfig({ withCache: false });
    if (!oauth.enabled) {
      throw new BadRequestException('OAuth is not enabled');
    }

    const expectedState = dto.state ?? this.getCookieOauthState(headers);
    if (!expectedState?.length) {

View on GitHub (pinned to 199723261c)

Solutions

  1. As admin, enable OAuth in Administration > Settings > OAuth and configure the issuer/clientId.
  2. Reload the web app so it fetches the fresh server config and hides the OAuth button.
  3. Verify the config persisted by re-opening Settings after save.
  4. If using env overrides, confirm OAUTH_ENABLED is not forced off.

Example fix

// before
await axios.post('/oauth/authorize', { redirectUri: 'https://app/callback' });

// after
// admin enables OAuth in UI first, then:
await axios.post('/oauth/authorize', { redirectUri: 'https://app/callback' });
Defensive patterns

Strategy: validation

Validate before calling

async function oauthEnabled(): Promise<boolean> {
  const { data } = await axios.get('/server/features');
  return data.config?.oauth?.enabled === true || data.oauth?.enabled === true;
}

Type guard

function isOauthEnabled(features: { oauth?: { enabled?: boolean } }): boolean {
  return features.oauth?.enabled === true;
}

Try / catch

try {
  await axios.post('/oauth/authorize', { redirectUri });
} catch (e) {
  if (e.response?.data?.message === 'OAuth is not enabled') {
    hideOauthButton();
  } else throw e;
}

Prevention

When it happens

Trigger: POST /oauth/authorize with body {redirectUri} before an admin has toggled OAuth enabled in server settings. The web login screen may show an OAuth button based on stale client config while the server has it disabled.

Common situations: Admin disabled OAuth after the web app cached the enabled state; OAuth config import/migration reset the flag; multi-instance deployment where the user hits a node with a different config.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/837a032591a3970c. Report an issue: GitHub.