FEAT: Implement Keycloak client with circuit breaker and retry logic for improved authentication resilience

This commit is contained in:
2025-06-17 14:50:34 +02:00
parent d436367ee6
commit 04ed9a094d
7 changed files with 598 additions and 72 deletions

View File

@@ -1,6 +1,9 @@
import { mkdir } from 'fs/promises'
import { existsSync } from 'fs'
import { join } from 'path'
import { keycloakClient } from '~/server/utils/keycloak-client'
let isAppReady = false
export default defineNitroPlugin(async (nitroApp) => {
console.log('[STARTUP] Server-side initialization starting...')
@@ -26,27 +29,57 @@ export default defineNitroPlugin(async (nitroApp) => {
}
// Check environment variables
console.log('[STARTUP] Checking OIDC environment variables...')
console.log('[STARTUP] Checking authentication environment variables...')
const requiredEnvVars = [
'NUXT_OIDC_TOKEN_KEY',
'NUXT_OIDC_SESSION_SECRET',
'NUXT_OIDC_AUTH_SESSION_SECRET',
'NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET'
'KEYCLOAK_CLIENT_SECRET',
'COOKIE_DOMAIN'
]
let envVarsOk = true
for (const envVar of requiredEnvVars) {
const value = process.env[envVar]
if (value) {
console.log(`[STARTUP] ✅ ${envVar}: present (length: ${value.length})`)
} else {
console.error(`[STARTUP] ❌ ${envVar}: MISSING`)
envVarsOk = false
}
}
console.log('[STARTUP] Server-side initialization complete')
if (!envVarsOk) {
console.error('[STARTUP] ❌ Required environment variables missing - authentication may fail')
}
// Warm up Keycloak connections
console.log('[STARTUP] Warming up Keycloak connections...')
try {
// Test the circuit breaker status endpoint (doesn't require auth)
const circuitStatus = keycloakClient.getCircuitBreakerStatus()
console.log('[STARTUP] ✅ Keycloak client initialized:', circuitStatus)
// Optionally test connectivity (uncomment if needed)
// const testUrl = 'https://auth.portnimara.dev/realms/client-portal/.well-known/openid-configuration'
// await keycloakClient.fetch(testUrl, {}, { timeout: 5000, retries: 1 })
// console.log('[STARTUP] ✅ Keycloak connectivity verified')
} catch (error) {
console.error('[STARTUP] ⚠️ Keycloak warmup failed:', error)
// Continue anyway - circuit breaker will handle runtime failures
}
// Mark app as ready
isAppReady = true
console.log('[STARTUP] ✅ Server-side initialization complete - app ready')
} catch (error) {
console.error('[STARTUP] Server-side initialization error:', error)
console.error('[STARTUP] Server-side initialization error:', error)
// Don't throw - let the app continue with fallback behavior
isAppReady = true // Allow app to start even with initialization errors
}
})
// Export readiness check for health endpoint
export const getAppReadiness = () => ({
ready: isAppReady,
keycloakCircuitBreaker: keycloakClient.getCircuitBreakerStatus()
})