immich-app/immich · error · Error
OAuth login failed
Error message
OAuth login failed
What it means
`getProfileAndOAuthSid` exchanges the OAuth code (or verifies the token) with the provider and fetches the user profile. Any failure in that flow — token exchange, profile fetch, network errors, provider rejections — is caught, logged, and rethrown as a generic Error('OAuth login failed') with the underlying error as `cause`. The generic message hides details, so the `cause` (and server logs) must be inspected to find the real reason.
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 5666d57f15)
Solutions
- Log/inspect `error.cause` (also check server logs — this.logger.error already logs the original error) to see the real provider failure.
- Verify the OAuth provider config: client_id, client_secret, issuer URL, and redirect URI exactly match the provider app registration.
- Test connectivity from the server to the provider's token/userinfo endpoints (curl the discovery URL) — self-hosted providers often fail due to Docker DNS/network isolation.
- Ensure the authorization code is single-use and recent: don't replay callback URLs or reuse codes.
- Check server clock sync (NTP) if tokens are rejected as expired.
Example fix
try {
await loginWithOAuth(code);
} catch (e) {
console.error('root cause:', (e as Error).cause); // see real provider error
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: verify provider discovery is reachable and config is set
const cfg = await fetch(`${issuerUrl}/.well-known/openid-configuration`).then(r => r.json());
if (!cfg.token_endpoint || !cfg.userinfo_endpoint) throw new Error('provider config incomplete'); Type guard
function hasCause(e: unknown): e is Error & { cause: unknown } {
return e instanceof Error && 'cause' in e;
} Try / catch
try {
const profile = await getProfileAndOAuthSid(code);
} catch (e) {
if (hasCause(e)) console.error('OAuth failure root cause:', e.cause);
// redirect user to login with a generic error; never expose provider details
} Prevention
- Always log/inspect error.cause — the message itself is generic.
- Validate client_id, client_secret, redirect_uri against the provider app registration before deploying.
- Never replay or cache authorization codes; they are single-use and short-lived.
- Test provider connectivity from inside the server's network/container.
- Keep server clocks NTP-synced to avoid token expiry rejections.
When it happens
Trigger: Calling the OAuth login endpoint with an invalid/expired/already-used authorization `code`; mismatched client_id/client_secret or redirect_uri vs. what the provider expects; the provider's token or userinfo endpoint being unreachable or returning 4xx/5xx; malformed id_token/access_token (wrong issuer, audience, expired); network failures to the provider.
Common situations: Incorrect OAuth client configuration in server settings (wrong client secret, redirect URI not registered); user taking too long and the code expiring; replaying a callback URL; provider outage or self-hosted provider (e.g. Authentik/Keycloak) behind DNS that the server can't resolve; clock skew invalidating tokens.
Related errors
- Error in OAuth discovery: ${error}
- Failed to verify SMTP configuration
- Invalid SMTP configuration
- Password login has been disabled
- Received backchannel logout request but OAuth is not enabled
AI-assisted analysis of immich-app/immich@5666d57f15 (2026-09-01).
Data as JSON: /api/errors/a9f9b5db52e5d39b.
Report an issue: GitHub.