export default defineEventHandler(async (event) => { const { code, state, error, error_description } = getQuery(event) as Record if (error) { console.warn('[auth/callback] Keycloak retornou erro:', error, error_description) return sendRedirect(event, `/?auth_error=${encodeURIComponent(error)}`, 302) } if (!code || !state) { return sendRedirect(event, '/?auth_error=missing_params', 302) } const pkceState = await consumePkceState(state) if (!pkceState) { return sendRedirect(event, '/?auth_error=invalid_state', 302) } try { const tokens = await exchangeCodeForTokens({ code, codeVerifier: pkceState.codeVerifier, redirectUri: callbackUrlFromEvent(event), }) const userInfo = userInfoFromAccessToken(tokens.access_token) const sid = await createSession({ accessToken: tokens.access_token, refreshToken: tokens.refresh_token, idToken: tokens.id_token, accessTokenExpiresAt: Date.now() + tokens.expires_in * 1000, userInfo, }) setSessionCookie(event, sid) return sendRedirect(event, pkceState.returnTo, 302) } catch (err) { console.error('[auth/callback] exchange falhou:', (err as Error).message) return sendRedirect(event, '/?auth_error=exchange_failed', 302) } })