import { keycloakClient } from '~/server/utils/keycloak-client' export default defineEventHandler(async (event) => { const startTime = Date.now() const query = getQuery(event) const { code, state, error } = query console.log('[KEYCLOAK] Callback received:', { code: !!code, state, error, requestId: event.node.req.headers['x-request-id'] || 'unknown' }) if (error) { const errorMsg = `Authentication failed: ${error}` console.error('[KEYCLOAK] OAuth error:', errorMsg) // Add timing info for debugging const duration = Date.now() - startTime console.error(`[KEYCLOAK] Failed after ${duration}ms`) throw createError({ statusCode: 400, statusMessage: errorMsg }) } if (!code) { const errorMsg = 'No authorization code received' console.error('[KEYCLOAK] ' + errorMsg) const duration = Date.now() - startTime console.error(`[KEYCLOAK] Failed after ${duration}ms`) throw createError({ statusCode: 400, statusMessage: errorMsg }) } try { console.log('[KEYCLOAK] Starting token exchange...') const redirectUri = 'https://client.portnimara.dev/api/auth/keycloak/callback' // Use the new Keycloak client with retry logic and circuit breaker const tokenResponse = await keycloakClient.exchangeCodeForTokens(code as string, redirectUri) const tokenExchangeDuration = Date.now() - startTime console.log(`[KEYCLOAK] Token exchange successful in ${tokenExchangeDuration}ms:`, { hasAccessToken: !!tokenResponse.access_token, hasRefreshToken: !!tokenResponse.refresh_token, expiresIn: tokenResponse.expires_in }) // Get user info with retry logic console.log('[KEYCLOAK] Fetching user info...') const userInfoStartTime = Date.now() const userInfo = await keycloakClient.getUserInfo(tokenResponse.access_token) const userInfoDuration = Date.now() - userInfoStartTime console.log(`[KEYCLOAK] User info retrieved in ${userInfoDuration}ms:`, { sub: userInfo.sub, email: userInfo.email, username: userInfo.preferred_username, name: userInfo.name }) // Set session cookie with proper configuration const sessionData = { user: { id: userInfo.sub, email: userInfo.email, username: userInfo.preferred_username || userInfo.email, name: userInfo.name || userInfo.preferred_username || userInfo.email, authMethod: 'keycloak' }, accessToken: tokenResponse.access_token, refreshToken: tokenResponse.refresh_token, expiresAt: Date.now() + (tokenResponse.expires_in * 1000), createdAt: Date.now() } // Create session cookie with proper session duration (8 hours = 28800 seconds) // Not tied to access token lifetime since we'll refresh tokens automatically const sessionDuration = 8 * 60 * 60; // 8 hours in seconds const cookieDomain = process.env.COOKIE_DOMAIN || '.portnimara.dev'; setCookie(event, 'nuxt-oidc-auth', JSON.stringify(sessionData), { httpOnly: true, secure: true, sameSite: 'lax', maxAge: sessionDuration, domain: cookieDomain, path: '/' }) const totalDuration = Date.now() - startTime console.log(`[KEYCLOAK] Authentication completed successfully in ${totalDuration}ms`) console.log('[KEYCLOAK] Session cookie set, redirecting to dashboard...') // Return HTML with client-side redirect for SPA compatibility setHeader(event, 'Content-Type', 'text/html') return `
Redirecting to dashboard...
If you are not redirected automatically, click here.