Skip to content

Commit 0b4825f

Browse files
committed
OIDC checking / retrying 2
1 parent cd9ba26 commit 0b4825f

File tree

3 files changed

+72
-29
lines changed

3 files changed

+72
-29
lines changed

server/app.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ let instance: any
162162
console.log(' Client ID:', process.env.VITE_OBP_OAUTH2_CLIENT_ID || 'NOT SET')
163163
console.log(' Redirect URI:', process.env.VITE_OBP_OAUTH2_REDIRECT_URL || 'NOT SET')
164164
console.log('OAuth2/OIDC ready for authentication')
165+
166+
// Start continuous monitoring even when initially connected
167+
oauth2Service.startHealthCheck(1000, 240000) // Monitor every 4 minutes
168+
console.log('OAuth2Service: Starting continuous monitoring (every 4 minutes)')
165169
} else {
166170
console.error('OAuth2Service: Initialization failed after all retries')
167171

@@ -176,7 +180,7 @@ let instance: any
176180
console.warn(' 3. Network connectivity to OIDC provider')
177181

178182
// Start periodic health check to reconnect when OIDC becomes available
179-
oauth2Service.startHealthCheck(1000) // Start with 1 second, then exponential backoff
183+
oauth2Service.startHealthCheck(1000, 240000) // Start with 1 second, monitor every 4 minutes when connected
180184
}
181185
}
182186
console.log(`-----------------------------------------------------------------`)

server/services/OAuth2Service.ts

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,17 @@ export class OAuth2Service {
211211
}
212212

213213
/**
214-
* Start periodic health check to reconnect if OIDC server becomes available
215-
* Uses exponential backoff: 1min, 2min, 4min, capped at 4min
214+
* Start periodic health check to monitor OIDC availability
215+
* Uses exponential backoff when reconnecting: 1s, 2s, 4s, up to 4min
216+
* Switches to regular monitoring (every 4 minutes) once connected
216217
*
217218
* @param {number} initialIntervalMs - Initial interval in milliseconds (default: 1000 = 1 second)
219+
* @param {number} monitoringIntervalMs - Interval for continuous monitoring when connected (default: 240000 = 4 minutes)
218220
*
219221
* @example
220-
* oauth2Service.startHealthCheck(1000) // Start checking at 1 second, then exponential backoff
222+
* oauth2Service.startHealthCheck(1000, 240000) // Start checking at 1 second, monitor every 4 minutes when connected
221223
*/
222-
startHealthCheck(initialIntervalMs: number = 1000): void {
224+
startHealthCheck(initialIntervalMs: number = 1000, monitoringIntervalMs: number = 240000): void {
223225
if (this.healthCheckInterval) {
224226
console.log('OAuth2Service: Health check already running')
225227
return
@@ -235,32 +237,70 @@ export class OAuth2Service {
235237
console.log('OAuth2Service: Starting health check with exponential backoff')
236238

237239
const scheduleNextCheck = () => {
238-
if (!this.initialized && this.wellKnownUrl) {
239-
// Calculate delay with exponential backoff, capped at 4 minutes
240-
const delay = Math.min(initialIntervalMs * Math.pow(2, this.healthCheckAttempts), 240000)
241-
const delayDisplay =
242-
delay < 60000
243-
? `${(delay / 1000).toFixed(0)} second(s)`
244-
: `${(delay / 60000).toFixed(1)} minute(s)`
240+
if (!this.wellKnownUrl) {
241+
return
242+
}
245243

244+
let delay: number
245+
246+
if (this.initialized) {
247+
// When connected, monitor every 4 minutes
248+
delay = monitoringIntervalMs
249+
} else {
250+
// When disconnected, use exponential backoff
251+
delay = Math.min(initialIntervalMs * Math.pow(2, this.healthCheckAttempts), 240000)
252+
}
253+
254+
const delayDisplay =
255+
delay < 60000
256+
? `${(delay / 1000).toFixed(0)} second(s)`
257+
: `${(delay / 60000).toFixed(1)} minute(s)`
258+
259+
if (this.initialized) {
260+
console.log(`OAuth2Service: Monitoring scheduled in ${delayDisplay}`)
261+
} else {
246262
console.log(
247263
`OAuth2Service: Health check scheduled in ${delayDisplay} (attempt ${this.healthCheckAttempts + 1})`
248264
)
265+
}
249266

250-
this.healthCheckInterval = setTimeout(async () => {
267+
this.healthCheckInterval = setTimeout(async () => {
268+
if (this.initialized) {
269+
// When connected, verify OIDC is still available
270+
console.log('OAuth2Service: Verifying OIDC availability...')
271+
try {
272+
const response = await fetch(this.wellKnownUrl)
273+
if (!response.ok) {
274+
throw new Error(`OIDC server returned ${response.status}`)
275+
}
276+
console.log('OAuth2Service: OIDC is available')
277+
// Continue monitoring
278+
scheduleNextCheck()
279+
} catch (error) {
280+
console.error('OAuth2Service: OIDC server is no longer available!')
281+
this.initialized = false
282+
this.oidcConfig = null
283+
this.healthCheckAttempts = 0
284+
console.log('OAuth2Service: Attempting to reconnect...')
285+
// Schedule reconnection with exponential backoff
286+
scheduleNextCheck()
287+
}
288+
} else {
289+
// When disconnected, attempt to reconnect
251290
console.log('OAuth2Service: Health check - attempting to reconnect to OIDC server...')
252291
try {
253292
await this.initializeFromWellKnown(this.wellKnownUrl)
254293
console.log('OAuth2Service: Successfully reconnected to OIDC server!')
255-
// Stop health check once reconnected
256-
this.stopHealthCheck()
294+
this.healthCheckAttempts = 0
295+
// Switch to continuous monitoring
296+
scheduleNextCheck()
257297
} catch (error) {
258298
this.healthCheckAttempts++
259-
// Schedule next check with longer interval
299+
// Schedule next reconnection attempt
260300
scheduleNextCheck()
261301
}
262-
}, delay)
263-
}
302+
}
303+
}, delay)
264304
}
265305

266306
// Start the first check

src/components/HeaderNav.vue

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,15 @@ async function checkOAuth2Availability() {
8787
try {
8888
const response = await fetch('/api/status/oauth2')
8989
const data = await response.json()
90+
const wasAvailable = oauth2Available.value
9091
oauth2Available.value = data.available
9192
oauth2StatusMessage.value = data.message || ''
9293
93-
if (data.available && oauth2CheckInterval) {
94-
// Stop polling once OAuth2 is available
95-
clearInterval(oauth2CheckInterval)
96-
oauth2CheckInterval = null
97-
console.log('OAuth2 is now available, stopped polling')
94+
// Log state changes
95+
if (!wasAvailable && data.available) {
96+
console.log('OAuth2 is now available')
97+
} else if (wasAvailable && !data.available) {
98+
console.warn('OAuth2 is no longer available!')
9899
}
99100
} catch (error) {
100101
oauth2Available.value = false
@@ -153,18 +154,16 @@ onMounted(async () => {
153154
// Initial OAuth2 availability check
154155
await checkOAuth2Availability()
155156
156-
// If OAuth2 is not available, poll every 30 seconds
157-
if (!oauth2Available.value) {
158-
console.log('OAuth2 not available, starting periodic check...')
159-
oauth2CheckInterval = window.setInterval(checkOAuth2Availability, 30000)
160-
}
157+
// Start continuous polling every 4 minutes to detect OIDC outages
158+
console.log('OAuth2: Starting continuous monitoring (every 4 minutes)...')
159+
oauth2CheckInterval = window.setInterval(checkOAuth2Availability, 240000) // 4 minutes
161160
162161
const currentUser = await getCurrentUser()
163162
const currentResponseKeys = Object.keys(currentUser)
164163
if (currentResponseKeys.includes('username')) {
164+
loginUsername.value = currentUser.username
165165
isShowLoginButton.value = false
166166
isShowLogOffButton.value = !isShowLoginButton.value
167-
loginUsername.value = currentUser.username
168167
} else {
169168
isShowLoginButton.value = true
170169
isShowLogOffButton.value = !isShowLoginButton.value

0 commit comments

Comments
 (0)