Skip to content

Commit 14f8ddf

Browse files
Yerazeclaude
andauthored
fix: OIDC init retries on failure instead of permanently disabling (#2402)
* fix: OIDC init retries on failure instead of permanently disabling If OIDC discovery failed (network timeout, provider briefly unavailable), isInitialized was set to true but oidcConfig stayed null — permanently disabling OIDC until container restart. This caused the login page to show "Local authentication is disabled and OIDC is not configured" after transient failures. Changes: - isOIDCEnabled() now returns true if OIDC was configured but init failed (so the OIDC login button stays visible) - Auto-retries up to 10 times at 30s intervals when discovery fails - Clears retry state on success Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add cleanupOIDC for graceful shutdown of retry timers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 42a2ede commit 14f8ddf

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

src/server/auth/oidcAuth.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@ import { getEnvironmentConfig } from '../config/environment.js';
1212

1313
let oidcConfig: client.Configuration | null = null;
1414
let isInitialized = false;
15+
let oidcWantedButFailed = false;
16+
let retryTimeout: ReturnType<typeof setTimeout> | null = null;
17+
const RETRY_DELAY_MS = 30_000; // Retry every 30 seconds on failure
18+
const MAX_RETRIES = 10;
19+
let retryCount = 0;
1520

1621
/**
1722
* Initialize OIDC client
1823
*/
1924
export async function initializeOIDC(): Promise<boolean> {
20-
if (isInitialized) {
21-
return oidcConfig !== null;
25+
if (isInitialized && oidcConfig !== null) {
26+
return true;
2227
}
2328

2429
const env = getEnvironmentConfig();
@@ -48,19 +53,53 @@ export async function initializeOIDC(): Promise<boolean> {
4853

4954
logger.debug('✅ OIDC client initialized successfully');
5055
isInitialized = true;
56+
oidcWantedButFailed = false;
57+
retryCount = 0;
5158
return true;
5259
} catch (error) {
5360
logger.error('❌ Failed to initialize OIDC client:', error);
61+
oidcWantedButFailed = true;
5462
isInitialized = true;
63+
scheduleRetry();
5564
return false;
5665
}
5766
}
5867

68+
/**
69+
* Schedule a retry of OIDC initialization after a transient failure
70+
*/
71+
function scheduleRetry(): void {
72+
if (retryTimeout) return; // Already scheduled
73+
if (retryCount >= MAX_RETRIES) {
74+
logger.error(`❌ OIDC initialization failed after ${MAX_RETRIES} retries — giving up. Restart the server to try again.`);
75+
return;
76+
}
77+
78+
retryCount++;
79+
logger.info(`🔄 Scheduling OIDC retry ${retryCount}/${MAX_RETRIES} in ${RETRY_DELAY_MS / 1000}s...`);
80+
retryTimeout = setTimeout(async () => {
81+
retryTimeout = null;
82+
isInitialized = false; // Allow re-initialization
83+
await initializeOIDC();
84+
}, RETRY_DELAY_MS);
85+
}
86+
87+
/**
88+
* Clean up pending retry timers for graceful shutdown
89+
*/
90+
export function cleanupOIDC(): void {
91+
if (retryTimeout) {
92+
clearTimeout(retryTimeout);
93+
retryTimeout = null;
94+
}
95+
}
96+
5997
/**
6098
* Check if OIDC is enabled and initialized
99+
* Returns true if OIDC is configured (even if init temporarily failed and is retrying)
61100
*/
62101
export function isOIDCEnabled(): boolean {
63-
return oidcConfig !== null;
102+
return oidcConfig !== null || oidcWantedButFailed;
64103
}
65104

66105
/**

0 commit comments

Comments
 (0)