// OAuth2 callback endpoint export default defineEventHandler(async (event) => { const config = useRuntimeConfig(); const query = getQuery(event); if (query.error) { throw createError({ statusCode: 400, message: query.error_description || 'Authentication failed' }); } if (!query.code) { throw createError({ statusCode: 400, message: 'No authorization code received' }); } try { // Exchange code for tokens const tokens = await $fetch(`${config.public.authentikUrl}/application/o/token/`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'authorization_code', code: query.code, redirect_uri: `${config.public.appUrl}/api/auth/callback`, client_id: config.authentik.clientId, client_secret: config.authentik.clientSecret }) }); // Get user info using access token const userInfo = await $fetch(`${config.public.authentikUrl}/application/o/userinfo/`, { headers: { 'Authorization': `Bearer ${tokens.access_token}` } }); // Set cookies setCookie(event, 'auth_token', tokens.access_token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 60 * 24 // 24 hours }); setCookie(event, 'refresh_token', tokens.refresh_token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 60 * 24 * 30 // 30 days }); // Store user info setCookie(event, 'user_info', JSON.stringify(userInfo), { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 60 * 24 // 24 hours }); // Redirect to dashboard return sendRedirect(event, '/dashboard'); } catch (error) { console.error('OAuth token exchange error:', error); throw createError({ statusCode: error.response?.status || 500, message: 'Failed to authenticate with Authentik' }); } });