// server/api/auth/login.post.ts /** * POST /api/auth/login * * Initiates OAuth2 Authorization Code Flow with PKCE * * Request body: * { * "email": "user@example.com" * } * * Response: * { * "redirectUrl": "https://experimenta.cidaas.de/authz-srv/authz?..." * } * * Client should redirect user to redirectUrl */ import { z } from 'zod' const loginSchema = z.object({ email: z.string().email('Invalid email address'), }) export default defineEventHandler(async (event) => { // 1. Validate request body const body = await readBody(event) const { email } = loginSchema.parse(body) // 2. Generate PKCE challenge const { verifier, challenge } = await generatePKCE() // 3. Generate state for CSRF protection const state = generateState(32) // 4. Store PKCE verifier in encrypted cookie (5 min TTL) setCookie(event, 'pkce_verifier', verifier, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 300, // 5 minutes path: '/', }) // 5. Store state in cookie for validation setCookie(event, 'oauth_state', state, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 300, // 5 minutes path: '/', }) // 6. Build Cidaas authorization URL const config = useRuntimeConfig() const authUrl = new URL(config.cidaas.authorizeUrl) authUrl.searchParams.set('client_id', config.cidaas.clientId) authUrl.searchParams.set('redirect_uri', config.cidaas.redirectUri) authUrl.searchParams.set('response_type', 'code') authUrl.searchParams.set('scope', 'openid profile email') authUrl.searchParams.set('state', state) authUrl.searchParams.set('code_challenge', challenge) authUrl.searchParams.set('code_challenge_method', 'S256') authUrl.searchParams.set('login_hint', email) // Pre-fill email in Cidaas form // 7. Return redirect URL to client return { redirectUrl: authUrl.toString(), } })