export default defineEventHandler(async (event) => { if (!authEnabled()) { throw createError({ statusCode: 404, statusMessage: 'Auth is not enabled' }) } const config = useRuntimeConfig() const query = getQuery(event) const code = String(query.code || '') const state = String(query.state || '') if (!code || !consumeOauthState(event, state)) { throw createError({ statusCode: 400, statusMessage: 'Invalid OAuth callback' }) } const redirectUri = `${publicBaseUrl(event)}/api/auth/callback` const tokenUrl = config.oidcTokenUrl || `${config.oidcIssuer}token/` const body = new URLSearchParams({ grant_type: 'authorization_code', code, redirect_uri: redirectUri, client_id: config.oidcClientId, client_secret: config.oidcClientSecret }) const tokenRes = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' }, body }) const tokenJson = await tokenRes.json().catch(() => ({})) as { access_token?: string; error?: string } if (!tokenRes.ok || !tokenJson.access_token) { throw createError({ statusCode: 401, statusMessage: 'OIDC token exchange failed' }) } const userinfoUrl = config.oidcUserinfoUrl || `${config.oidcIssuer}userinfo/` const userRes = await fetch(userinfoUrl, { headers: { Authorization: `Bearer ${tokenJson.access_token}` } }) const user = await userRes.json().catch(() => ({})) as { sub?: string; email?: string; name?: string; preferred_username?: string } if (!userRes.ok || !user.sub) { throw createError({ statusCode: 401, statusMessage: 'OIDC userinfo failed' }) } setSessionUser(event, { sub: user.sub, email: user.email, name: user.name || user.preferred_username || user.email }) await sendRedirect(event, '/', 302) })