FEAT: Migrate authentication system from Directus to Keycloak, implementing token refresh and enhancing session management
This commit is contained in:
@@ -21,6 +21,16 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Validate environment variables
|
||||
const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET
|
||||
if (!clientSecret) {
|
||||
console.error('[KEYCLOAK] KEYCLOAK_CLIENT_SECRET not configured')
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Authentication service misconfigured'
|
||||
})
|
||||
}
|
||||
|
||||
// Exchange authorization code for tokens
|
||||
const tokenResponse = await $fetch('https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/token', {
|
||||
method: 'POST',
|
||||
@@ -30,13 +40,17 @@ export default defineEventHandler(async (event) => {
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
client_id: 'client-portal',
|
||||
client_secret: process.env.KEYCLOAK_CLIENT_SECRET || '',
|
||||
client_secret: clientSecret,
|
||||
code: code as string,
|
||||
redirect_uri: 'https://client.portnimara.dev/api/auth/keycloak/callback'
|
||||
}).toString()
|
||||
}) as any
|
||||
|
||||
console.log('[KEYCLOAK] Token exchange successful')
|
||||
console.log('[KEYCLOAK] Token exchange successful:', {
|
||||
hasAccessToken: !!tokenResponse.access_token,
|
||||
hasRefreshToken: !!tokenResponse.refresh_token,
|
||||
expiresIn: tokenResponse.expires_in
|
||||
})
|
||||
|
||||
// Get user info
|
||||
const userInfo = await $fetch('https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/userinfo', {
|
||||
@@ -48,35 +62,50 @@ export default defineEventHandler(async (event) => {
|
||||
console.log('[KEYCLOAK] User info retrieved:', {
|
||||
sub: userInfo.sub,
|
||||
email: userInfo.email,
|
||||
username: userInfo.preferred_username
|
||||
username: userInfo.preferred_username,
|
||||
name: userInfo.name
|
||||
})
|
||||
|
||||
// Set session cookie
|
||||
// Set session cookie with proper configuration
|
||||
const sessionData = {
|
||||
user: userInfo,
|
||||
user: {
|
||||
id: userInfo.sub,
|
||||
email: userInfo.email,
|
||||
username: userInfo.preferred_username || userInfo.email,
|
||||
name: userInfo.name || userInfo.preferred_username || userInfo.email,
|
||||
authMethod: 'keycloak'
|
||||
},
|
||||
accessToken: tokenResponse.access_token,
|
||||
refreshToken: tokenResponse.refresh_token,
|
||||
expiresAt: Date.now() + (tokenResponse.expires_in * 1000)
|
||||
expiresAt: Date.now() + (tokenResponse.expires_in * 1000),
|
||||
createdAt: Date.now()
|
||||
}
|
||||
|
||||
// Create a simple session using a secure cookie
|
||||
// Create session cookie with better security settings
|
||||
setCookie(event, 'nuxt-oidc-auth', JSON.stringify(sessionData), {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'lax',
|
||||
maxAge: tokenResponse.expires_in
|
||||
maxAge: tokenResponse.expires_in,
|
||||
domain: '.portnimara.dev',
|
||||
path: '/'
|
||||
})
|
||||
|
||||
console.log('[OIDC] Session cookie set, redirecting to dashboard')
|
||||
console.log('[KEYCLOAK] Session cookie set successfully')
|
||||
console.log('[KEYCLOAK] Redirecting to dashboard...')
|
||||
|
||||
// Redirect to dashboard
|
||||
await sendRedirect(event, '/dashboard')
|
||||
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('[KEYCLOAK] Token exchange failed:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Authentication failed during token exchange'
|
||||
console.error('[KEYCLOAK] Error details:', {
|
||||
message: error.message,
|
||||
status: error.status,
|
||||
data: error.data
|
||||
})
|
||||
|
||||
// Redirect to login with error
|
||||
await sendRedirect(event, '/login?error=auth_failed')
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user