Implement Official Keycloak JS Adapter with Proxy-Aware Configuration
MAJOR ENHANCEMENT: Complete Keycloak integration with proper HTTPS/proxy handling ## Core Improvements: ### 1. Enhanced Configuration (nuxt.config.ts) - Added proxy trust configuration for nginx environments - Configured baseUrl for production HTTPS enforcement - Added debug mode configuration for development ### 2. Proxy-Aware Keycloak Composable (composables/useKeycloak.ts) - Intelligent base URL detection (production vs development) - Force HTTPS redirect URIs in production environments - Enhanced debugging and logging capabilities - Proper PKCE implementation for security - Automatic token refresh mechanism ### 3. Dual Authentication System - Updated middleware to support both Directus and Keycloak - Enhanced useUnifiedAuth for seamless auth source switching - Maintains backward compatibility with existing Directus users ### 4. OAuth Flow Implementation - Created proper callback handler (pages/auth/callback.vue) - Comprehensive error handling and user feedback - Automatic redirect to dashboard on success ### 5. Enhanced Login Experience (pages/login.vue) - Restored SSO login button with proper error handling - Maintained existing Directus login form - Clear separation between auth methods with visual divider ### 6. Comprehensive Testing Suite (pages/dashboard/keycloak-test.vue) - Real-time configuration display - Authentication status monitoring - Interactive testing tools - Detailed debug logging system ## Technical Solutions: **Proxy Detection**: Automatically detects nginx proxy and uses correct HTTPS URLs **HTTPS Enforcement**: Forces secure redirect URIs in production **Error Handling**: Comprehensive error catching with user-friendly messages **Debug Capabilities**: Enhanced logging for troubleshooting **Security**: Implements PKCE and secure token handling ## Infrastructure Compatibility: - Works with nginx reverse proxy setups - Compatible with Docker container networking - Handles SSL termination at proxy level - Supports both development and production environments This implementation specifically addresses the HTTP/HTTPS redirect URI mismatch that was causing 'unauthorized_client' errors in the proxy environment.
This commit is contained in:
79
pages/auth/callback.vue
Normal file
79
pages/auth/callback.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center" class="fill-height">
|
||||
<v-col cols="12" class="text-center">
|
||||
<v-progress-circular
|
||||
:size="70"
|
||||
:width="7"
|
||||
color="primary"
|
||||
indeterminate
|
||||
></v-progress-circular>
|
||||
<h3 class="mt-4">Processing authentication...</h3>
|
||||
<p class="text-body-2 mt-2">Please wait while we complete your login</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Define page meta for public access (no auth required)
|
||||
definePageMeta({
|
||||
auth: false,
|
||||
layout: false
|
||||
});
|
||||
|
||||
// Handle OAuth callback
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const route = useRoute()
|
||||
const keycloak = useKeycloak()
|
||||
|
||||
// Check if we have an authorization code
|
||||
const code = route.query.code as string
|
||||
const state = route.query.state as string
|
||||
const error = route.query.error as string
|
||||
|
||||
if (error) {
|
||||
console.error('OAuth error:', error, route.query.error_description)
|
||||
throw new Error(`Authentication failed: ${error}`)
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
throw new Error('No authorization code received')
|
||||
}
|
||||
|
||||
console.log('[CALLBACK] Processing OAuth callback with code:', code.substring(0, 10) + '...')
|
||||
|
||||
// Initialize Keycloak if not already done
|
||||
if (!keycloak.isInitialized.value) {
|
||||
await keycloak.initKeycloak()
|
||||
}
|
||||
|
||||
// Check if user is now authenticated
|
||||
if (keycloak.isAuthenticated.value) {
|
||||
console.log('[CALLBACK] User authenticated successfully')
|
||||
// Redirect to dashboard
|
||||
await navigateTo('/dashboard')
|
||||
} else {
|
||||
throw new Error('Authentication process failed')
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[CALLBACK] Authentication error:', error)
|
||||
|
||||
// Show error and redirect to login
|
||||
const toast = useToast()
|
||||
toast.error('Authentication failed. Unable to complete login. Please try again.')
|
||||
|
||||
await navigateTo('/login')
|
||||
}
|
||||
})
|
||||
|
||||
useHead({
|
||||
title: 'Authenticating...'
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user