You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
1.9 KiB
73 lines
1.9 KiB
// 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(),
|
|
}
|
|
})
|
|
|