export default defineEventHandler(async (event) => { const query = getQuery(event) const { code, state, error } = query console.log('[KEYCLOAK] Callback received:', { code: !!code, state, error }) if (error) { console.error('[KEYCLOAK] OAuth error:', error) throw createError({ statusCode: 400, statusMessage: `Authentication failed: ${error}` }) } if (!code) { console.error('[KEYCLOAK] No authorization code received') throw createError({ statusCode: 400, statusMessage: 'No authorization code received' }) } try { // Exchange authorization code for tokens const tokenResponse = await $fetch('https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'authorization_code', client_id: 'client-portal', client_secret: process.env.KEYCLOAK_CLIENT_SECRET || '', code: code as string, redirect_uri: 'https://client.portnimara.dev/api/auth/keycloak/callback' }).toString() }) as any console.log('[KEYCLOAK] Token exchange successful') // Get user info const userInfo = await $fetch('https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/userinfo', { headers: { 'Authorization': `Bearer ${tokenResponse.access_token}` } }) as any console.log('[KEYCLOAK] User info retrieved:', { sub: userInfo.sub, email: userInfo.email, username: userInfo.preferred_username }) // Set session cookie const sessionData = { user: userInfo, accessToken: tokenResponse.access_token, refreshToken: tokenResponse.refresh_token, expiresAt: Date.now() + (tokenResponse.expires_in * 1000) } // Create a simple session using a secure cookie setCookie(event, 'keycloak-session', JSON.stringify(sessionData), { httpOnly: true, secure: true, sameSite: 'lax', maxAge: tokenResponse.expires_in }) console.log('[KEYCLOAK] Session cookie set, redirecting to dashboard') // Redirect to dashboard await sendRedirect(event, '/dashboard') } catch (error) { console.error('[KEYCLOAK] Token exchange failed:', error) throw createError({ statusCode: 500, statusMessage: 'Authentication failed during token exchange' }) } })