🔧 FIX: Disable OIDC global middleware to prevent redirect loops

CRITICAL FIX: The nuxt-oidc-auth module was causing infinite redirect loops
because its global middleware was active on ALL pages, including /login.

## 🚨 **Problem Solved:**
- Login page was redirecting to itself infinitely
- OIDC module auto-authenticating on every route
- 502 Bad Gateway errors from redirect loops

##  **Changes Made:**

### **nuxt.config.ts:**
- Added globalMiddlewareEnabled: false to OIDC middleware config
- This disables automatic authentication on all routes
- Prevents redirect loops on login page

### **Cleanup:**
- Removed obsolete pages/dashboard/keycloak-test.vue
- Fixed TypeScript errors from missing useKeycloak composable

## 🎯 **Result:**
 Login page should now load without redirect loops
 SSO button should work properly when clicked
 Manual authentication control via our middleware
 Maintains Directus auth compatibility

## 📋 **Next Steps:**
1. Rebuild container in Portainer with these changes
2. Test login page loads properly
3. Test SSO authentication flow
4. Verify no more 502 errors on callback

This fixes the core issue blocking the Keycloak SSO integration!
This commit is contained in:
Matt 2025-06-14 16:07:01 +02:00
parent 0ae190b255
commit 12403233c0
2 changed files with 3 additions and 249 deletions

View File

@ -112,6 +112,9 @@ export default defineNuxtConfig({
}
},
oidc: {
middleware: {
globalMiddlewareEnabled: false, // Disable automatic middleware - prevents redirect loops!
},
providers: {
keycloak: {
audience: 'account',

View File

@ -1,249 +0,0 @@
<template>
<v-container>
<v-row>
<v-col cols="12">
<h1>Keycloak Integration Test</h1>
<p class="text-body-1 mb-6">Test the Keycloak SSO integration and debug any issues</p>
</v-col>
</v-row>
<v-row>
<!-- Configuration Display -->
<v-col cols="12" md="6">
<v-card>
<v-card-title>Configuration</v-card-title>
<v-card-text>
<pre class="text-caption">{{ configInfo }}</pre>
</v-card-text>
</v-card>
</v-col>
<!-- Status Display -->
<v-col cols="12" md="6">
<v-card>
<v-card-title>Current Status</v-card-title>
<v-card-text>
<v-chip
:color="keycloak.isInitialized.value ? 'green' : 'red'"
variant="tonal"
class="mb-2"
>
Initialized: {{ keycloak.isInitialized.value }}
</v-chip>
<br>
<v-chip
:color="keycloak.isAuthenticated.value ? 'green' : 'red'"
variant="tonal"
class="mb-2"
>
Authenticated: {{ keycloak.isAuthenticated.value }}
</v-chip>
<br>
<v-chip
:color="unifiedAuth.user.value ? 'green' : 'gray'"
variant="tonal"
class="mb-2"
>
Auth Source: {{ unifiedAuth.authSource.value || 'None' }}
</v-chip>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row class="mt-4">
<!-- User Information -->
<v-col cols="12" md="6" v-if="unifiedAuth.user.value">
<v-card>
<v-card-title>User Information</v-card-title>
<v-card-text>
<pre class="text-caption">{{ JSON.stringify(unifiedAuth.user.value, null, 2) }}</pre>
</v-card-text>
</v-card>
</v-col>
<!-- Actions -->
<v-col cols="12" md="6">
<v-card>
<v-card-title>Actions</v-card-title>
<v-card-text class="d-flex flex-column ga-3">
<v-btn
@click="initializeKeycloak"
:loading="initializing"
variant="outlined"
color="primary"
>
Initialize Keycloak
</v-btn>
<v-btn
@click="testLogin"
:loading="loginTesting"
variant="outlined"
color="success"
:disabled="!keycloak.isInitialized.value"
>
Test Login
</v-btn>
<v-btn
@click="testLogout"
variant="outlined"
color="warning"
:disabled="!keycloak.isAuthenticated.value"
>
Test Logout
</v-btn>
<v-btn
@click="refreshStatus"
variant="outlined"
>
Refresh Status
</v-btn>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row class="mt-4">
<!-- Debug Logs -->
<v-col cols="12">
<v-card>
<v-card-title>
Debug Logs
<v-spacer></v-spacer>
<v-btn @click="clearLogs" size="small" variant="text">Clear</v-btn>
</v-card-title>
<v-card-text>
<v-sheet class="pa-3" style="background-color: #1e1e1e; color: #fff; height: 300px; overflow-y: auto;">
<div v-for="(log, index) in logs" :key="index" class="text-caption">
<span :style="{ color: getLogColor(log.level) }">
[{{ log.timestamp }}] {{ log.level.toUpperCase() }}: {{ log.message }}
</span>
<pre v-if="log.data" class="text-caption mt-1" style="color: #ccc;">{{ JSON.stringify(log.data, null, 2) }}</pre>
</div>
</v-sheet>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup lang="ts">
// Auth systems
const keycloak = useKeycloak()
const unifiedAuth = useUnifiedAuth()
const config = useRuntimeConfig()
// Reactive state
const initializing = ref(false)
const loginTesting = ref(false)
const logs = ref<Array<{level: string, message: string, data?: any, timestamp: string}>>([])
// Computed properties
const configInfo = computed(() => ({
keycloakUrl: config.public.keycloak.url,
realm: config.public.keycloak.realm,
clientId: config.public.keycloak.clientId,
baseUrl: config.public.baseUrl,
debug: config.public.keycloakDebug,
currentOrigin: process.client ? window.location.origin : 'N/A (SSR)',
userAgent: process.client ? navigator.userAgent : 'N/A (SSR)'
}))
// Logging functions
const addLog = (level: string, message: string, data?: any) => {
logs.value.push({
level,
message,
data,
timestamp: new Date().toLocaleTimeString()
})
// Keep only last 50 logs
if (logs.value.length > 50) {
logs.value = logs.value.slice(-50)
}
}
const getLogColor = (level: string) => {
switch (level) {
case 'error': return '#ff5252'
case 'warn': return '#ff9800'
case 'info': return '#2196f3'
case 'success': return '#4caf50'
default: return '#fff'
}
}
const clearLogs = () => {
logs.value = []
}
// Test functions
const initializeKeycloak = async () => {
try {
initializing.value = true
addLog('info', 'Initializing Keycloak...')
const result = await keycloak.initKeycloak()
addLog('success', `Keycloak initialized. Authenticated: ${result}`, {
initialized: keycloak.isInitialized.value,
authenticated: keycloak.isAuthenticated.value
})
} catch (error) {
addLog('error', 'Keycloak initialization failed', error)
} finally {
initializing.value = false
}
}
const testLogin = async () => {
try {
loginTesting.value = true
addLog('info', 'Starting login test...')
await keycloak.login()
} catch (error) {
addLog('error', 'Login test failed', error)
loginTesting.value = false
}
}
const testLogout = async () => {
try {
addLog('info', 'Starting logout test...')
await keycloak.logout()
addLog('success', 'Logout completed')
} catch (error) {
addLog('error', 'Logout failed', error)
}
}
const refreshStatus = () => {
addLog('info', 'Refreshing status...', {
keycloakInitialized: keycloak.isInitialized.value,
keycloakAuthenticated: keycloak.isAuthenticated.value,
unifiedUser: unifiedAuth.user.value,
authSource: unifiedAuth.authSource.value
})
}
// Initialize on mount
onMounted(() => {
addLog('info', 'Keycloak test page loaded')
refreshStatus()
})
useHead({
title: 'Keycloak Integration Test'
})
</script>