immich-app/immich · error

OAuth login failed

Error message

OAuth login failed

What it means

getProfileAndOAuthSid wraps any failure during the OAuth code exchange / token verification / profile retrieval into a single 'OAuth login failed' error, preserving the underlying cause. It is a top-level umbrella error for the whole OIDC login flow, so the original error is attached as `cause` and logged.

Solutions

  1. Inspect the `cause` property / server logs ('OAuth login failed' with error) for the real failure
  2. Verify clientId, clientSecret, and redirect URI match the provider's registered app settings
  3. Check token endpoint auth method configuration matches what the provider expects
  4. Confirm server clock is NTP-synchronized and the provider is reachable from the server

Example fix

// before
try { login(); } catch (e) { console.log(e.message); } // 'OAuth login failed'
// after
try { login(); } catch (e) { console.log(e.message, e.cause); } // surfaces root cause
Defensive patterns

Strategy: try-catch

Validate before calling

// before redirecting, sanity-check config
assert(clientId && clientSecret, 'OAuth client credentials missing');
assert(registeredRedirectUris.includes(redirectUri), 'redirectUri not registered with provider');

Type guard

const hasCause = (e: unknown): e is Error & { cause?: unknown } => e instanceof Error && 'cause' in e;

Try / catch

try {
  await oauthRepo.getProfileAndOAuthSid(tokens);
} catch (e) {
  logger.error('OAuth login failed', { cause: (e as any).cause ?? e });
  return redirect('/login?error=oauth');
}

Prevention

When it happens

Trigger: Any exception inside the login flow: code/token exchange failure, ID token verification failure (bad issuer/audience/expiry), PKCE mismatch, client authentication rejection, or profile fetch failure during getProfileAndOAuthSid().

Common situations: Wrong client secret after rotation; redirect URI mismatch causing token exchange rejection; clock skew making tokens 'expired'; provider outage; state/PKCE verifier lost across a scaled deployment; user denied consent at the provider.

Related errors


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

Appendix: source

Thrown at server/src/repositories/oauth.repository.ts:128

        if (typeof claims?.sid === 'string') {
          sid = claims.sid;
        }
      }

      return { profile, sid, idToken: tokens.id_token };
    } catch (error: Error | any) {
      if (error.message.includes('unexpected JWT alg received')) {
        this.logger.warn(
          [
            'Algorithm mismatch. Make sure the signing algorithm is set correctly in the OAuth settings.',
            'Or, that you have specified a signing key in your OAuth provider.',
          ].join(' '),
        );
      }

      this.logger.error('OAuth login failed', error);

      throw new Error('OAuth login failed', { cause: error });
    }
  }

  async getProfilePicture(url: string) {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`Failed to fetch picture: ${response.statusText}`);
    }

    return response.arrayBuffer();
  }

  private jwksClients: Map<string, JWTVerifyGetKey> = new Map(); // useful for caching and performnce
  async validateLogoutToken(config: OAuthConfig, logoutToken: string): Promise<{ sub?: string; sid?: string } | null> {
    const client = await this.getClient(config);
    const algorithm = client.clientMetadata().id_token_signed_response_alg ?? 'RS256';
    let keyOrGetter: Uint8Array | JWTVerifyGetKey;

View on GitHub (pinned to e55ac299a4)