From 3a038128018b06b77435fed4e1aa48bc94e48d46 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sun, 28 Dec 2025 15:38:13 +0100 Subject: [PATCH] Add multi-provider login UI to HeaderNav - Fetch available providers from /api/oauth2/providers on mount - Show provider selection dialog when multiple providers available - Direct login when only one provider available - Fallback to legacy mode when no providers configured - Display provider icons and formatted names - Responsive provider selection dialog with hover effects - Maintain backward compatibility with single-provider mode --- src/components/HeaderNav.vue | 188 ++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-) diff --git a/src/components/HeaderNav.vue b/src/components/HeaderNav.vue index 037f7f3..12d9092 100644 --- a/src/components/HeaderNav.vue +++ b/src/components/HeaderNav.vue @@ -80,6 +80,11 @@ const logo = ref(logoSource) const headerLinksHoverColor = ref(headerLinksHoverColorSetting) const headerLinksBackgroundColor = ref(headerLinksBackgroundColorSetting) +// Multi-provider support +const availableProviders = ref>([]) +const showProviderSelector = ref(false) +const isLoadingProviders = ref(false) + // Check OAuth2 availability let oauth2CheckInterval: number | null = null @@ -104,6 +109,74 @@ async function checkOAuth2Availability() { } } +// Fetch available OIDC providers +async function fetchAvailableProviders() { + isLoadingProviders.value = true + try { + const response = await fetch('/api/oauth2/providers') + const data = await response.json() + + if (data.providers && Array.isArray(data.providers)) { + availableProviders.value = data.providers + console.log('Available OAuth2 providers:', availableProviders.value) + console.log(`Total: ${data.count}, Available: ${data.availableCount}`) + } else { + console.warn('No providers returned from /api/oauth2/providers') + availableProviders.value = [] + } + } catch (error) { + console.error('Failed to fetch OAuth2 providers:', error) + availableProviders.value = [] + } finally { + isLoadingProviders.value = false + } +} + +// Handle login button click +function handleLoginClick() { + const available = availableProviders.value.filter(p => p.available) + + if (available.length > 1) { + // Show provider selection dialog + showProviderSelector.value = true + } else if (available.length === 1) { + // Direct login with single provider + loginWithProvider(available[0].name) + } else { + // Fallback to legacy login (no provider parameter) + window.location.href = '/api/oauth2/connect?redirect=' + encodeURIComponent(getCurrentPath()) + } +} + +// Login with selected provider +function loginWithProvider(provider: string) { + const redirectUrl = '/api/oauth2/connect?provider=' + + encodeURIComponent(provider) + + '&redirect=' + + encodeURIComponent(getCurrentPath()) + console.log(`Logging in with provider: ${provider}`) + window.location.href = redirectUrl +} + +// Format provider name for display +function formatProviderName(name: string): string { + // Convert "obp-oidc" to "OBP OIDC", "keycloak" to "Keycloak", etc. + return name.split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ') +} + +// Get provider icon +function getProviderIcon(name: string): string { + const icons: Record = { + 'obp-oidc': '🏦', + 'keycloak': '🔐', + 'google': '🔵', + 'github': '🐙' + } + return icons[name] || '🔑' +} + const clearActiveTab = () => { const activeLinks = document.querySelectorAll('.router-link') for (const active of activeLinks) { @@ -154,6 +227,9 @@ onMounted(async () => { // Initial OAuth2 availability check await checkOAuth2Availability() + // Fetch available providers + await fetchAvailableProviders() + // Start continuous polling every 4 minutes to detect OIDC outages console.log('OAuth2: Starting continuous monitoring (every 4 minutes)...') oauth2CheckInterval = window.setInterval(checkOAuth2Availability, 240000) // 4 minutes @@ -249,15 +325,50 @@ const getCurrentPath = () => { {{ $t('header.login') }} - {{ $t('header.logoff') }} + + + +
+
+
{{ getProviderIcon(provider.name) }}
+
+

{{ formatProviderName(provider.name) }}

+ Available +
+
+
+ +
+

No identity providers available

+

Please contact your administrator

+
+
+