export default defineEventHandler(async (event) => { console.log('🔄 Callback endpoint called at:', new Date().toISOString()); const query = getQuery(event); const { code, state } = query; console.log('📝 Callback query params:', { hasCode: !!code, hasState: !!state, state: state ? 'present' : 'missing' }); if (!code || !state) { throw createError({ statusCode: 400, statusMessage: 'Missing authorization code or state', }); } // Verify state const storedState = getCookie(event, 'oauth-state'); if (state !== storedState) { throw createError({ statusCode: 400, statusMessage: 'Invalid state parameter', }); } try { const keycloak = createKeycloakClient(); const sessionManager = createSessionManager(); // Exchange code for tokens const tokens = await keycloak.exchangeCodeForTokens(code as string); // Get user info const userInfo = await keycloak.getUserInfo(tokens.access_token); // Use member-tiers service for proper tier determination const { determineMemberTierByEmail, determineMemberTierFromKeycloak } = await import('~/server/utils/member-tiers'); // First try to determine tier by email (checks NocoDB and Keycloak) const tierResult = await determineMemberTierByEmail(userInfo.email); // Log tier determination for monitoring console.log(`[auth-callback] Tier determination for ${userInfo.email}:`, { tier: tierResult.tier, source: tierResult.source, confidence: tierResult.confidence, reason: tierResult.reason }); // Alert admin if tier confidence is low if (tierResult.confidence === 'low') { console.warn(`[auth-callback] Low confidence tier assignment for ${userInfo.email}. Manual review recommended.`); } // Create session const sessionData = { user: { id: userInfo.sub, email: userInfo.email, name: userInfo.name || `${userInfo.given_name || ''} ${userInfo.family_name || ''}`.trim(), firstName: userInfo.given_name, lastName: userInfo.family_name, username: userInfo.preferred_username, tier: tierResult.tier, tierSource: tierResult.source, // Track where tier came from groups: userInfo.groups || ['user'], }, tokens: { accessToken: tokens.access_token, refreshToken: tokens.refresh_token, expiresAt: Date.now() + (tokens.expires_in * 1000), }, createdAt: Date.now(), lastActivity: Date.now(), }; const sessionCookie = sessionManager.createSession(sessionData); // Set session cookie setHeader(event, 'Set-Cookie', sessionCookie); // Clear state cookie deleteCookie(event, 'oauth-state'); return sendRedirect(event, '/dashboard'); } catch (error) { console.error('Auth callback error:', error); throw createError({ statusCode: 500, statusMessage: 'Authentication failed', }); } });