Files
web-antrean/server/api/auth/keycloak-login.ts
T
2026-01-30 15:11:17 +07:00

115 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/api/auth/keycloak-login.ts
import { randomBytes } from 'crypto'
export default defineEventHandler(async (event) => {
console.log('🔐 Keycloak Login Handler Called')
console.log('📍 Method:', getMethod(event))
// === STALE SESSION CLEANUP ===
// Check for existing session and clean up if invalid/expired
const existingSessionId = getCookie(event, 'user_session')
if (existingSessionId) {
console.log('🔍 Existing session cookie found, validating...')
try {
const { getSession, deleteSession } = await import('~/server/utils/sessionStore')
const session = getSession(existingSessionId)
if (session) {
// Check if session is expired
const isExpired = Date.now() > session.expiresAt
if (isExpired) {
console.log('🧹 Cleaning up expired session...')
deleteSession(existingSessionId)
deleteCookie(event, 'user_session')
deleteCookie(event, 'oauth_state')
console.log('✅ Expired session cleared')
} else {
console.log('⚠️ Valid session exists, clearing to allow fresh login...')
deleteSession(existingSessionId)
deleteCookie(event, 'user_session')
deleteCookie(event, 'oauth_state')
console.log('✅ Existing session cleared for fresh login')
}
} else {
console.log('🧹 Session cookie exists but no session in store, clearing cookie...')
deleteCookie(event, 'user_session')
deleteCookie(event, 'oauth_state')
console.log('✅ Stale cookie cleared')
}
} catch (error) {
console.warn('⚠️ Error during session cleanup:', error)
// Clear cookies anyway to be safe
deleteCookie(event, 'user_session')
deleteCookie(event, 'oauth_state')
}
} else {
console.log('️ No existing session found, proceeding with fresh login')
}
// === END STALE SESSION CLEANUP ===
try {
const config = useRuntimeConfig()
// Debug: Log runtime config (without secrets)
console.log('🔧 Runtime Config Check:')
console.log(' - Has keycloakIssuer:', !!config.keycloakIssuer)
console.log(' - Has keycloakClientId:', !!config.keycloakClientId)
console.log(' - Has keycloakSecret:', !!config.keycloakClientSecret)
console.log(' - Issuer value:', config.keycloakIssuer)
// Validate required configuration
if (!config.keycloakIssuer) {
throw new Error('KEYCLOAK_ISSUER is not configured')
}
if (!config.keycloakClientId) {
throw new Error('KEYCLOAK_CLIENT_ID is not configured')
}
// Generate state parameter for security
const state = randomBytes(32).toString('hex')
console.log('🎲 Generated state:', state.substring(0, 8) + '...')
// Store state in session cookie
setCookie(event, 'oauth_state', state, {
httpOnly: true,
secure: false,
sameSite: 'lax',
maxAge: 600 // 10 minutes
})
// Build Keycloak authorization URL
const redirectUri = `${config.public.authUrl}/api/auth/keycloak-callback`
// Debug: Log the redirect URI being used
console.log('🔧 AUTH_ORIGIN from config:', config.public.authUrl)
console.log('🔗 Redirect URI being sent to Keycloak:', redirectUri)
const authUrl = new URL(`${config.keycloakIssuer}/protocol/openid-connect/auth`)
authUrl.searchParams.set('client_id', config.keycloakClientId)
authUrl.searchParams.set('redirect_uri', redirectUri)
authUrl.searchParams.set('response_type', 'code')
authUrl.searchParams.set('scope', 'openid profile email')
authUrl.searchParams.set('state', state)
console.log('🏗️ Auth URL built:', authUrl.toString())
return {
success: true,
data: {
authUrl: authUrl.toString()
}
}
} catch (error: any) {
console.error('❌ Login Error:', error.message)
throw createError({
statusCode: 500,
statusMessage: `Failed to generate authorization URL: ${error.message}`
})
}
})