mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-14 10:34:06 +02:00
Fixes bug where SSO login with custom providers caused an `InvalidClientRegistrationIdException: Invalid Client Registration with Id: oidc` errors. Root Cause: - Backend: Redirect URI was hardcoded to `/login/oauth2/code/oidc` regardless of provider registration ID - Frontend: Unknown providers were mapped back to 'oidc' instead of using actual provider ID Closes #5141 --------- Co-authored-by: Anthony Stirling <[email protected]> Co-authored-by: Keon Chen <[email protected]>
117 lines
3.9 KiB
TypeScript
117 lines
3.9 KiB
TypeScript
import { useTranslation } from 'react-i18next';
|
|
import { BASE_PATH } from '@app/constants/app';
|
|
import { type OAuthProvider } from '@app/auth/oauthTypes';
|
|
|
|
// Debug flag to show all providers for UI testing
|
|
// Set to true to see all SSO options regardless of backend configuration
|
|
export const DEBUG_SHOW_ALL_PROVIDERS = false;
|
|
|
|
// OAuth provider configuration - maps provider ID to display info
|
|
// Known providers get custom icons; unknown providers use generic SSO icon
|
|
export const oauthProviderConfig: Record<string, { label: string; file: string }> = {
|
|
google: { label: 'Google', file: 'google.svg' },
|
|
github: { label: 'GitHub', file: 'github.svg' },
|
|
apple: { label: 'Apple', file: 'apple.svg' },
|
|
azure: { label: 'Microsoft', file: 'microsoft.svg' },
|
|
keycloak: { label: 'Keycloak', file: 'keycloak.svg' },
|
|
cloudron: { label: 'Cloudron', file: 'cloudron.svg' },
|
|
authentik: { label: 'Authentik', file: 'authentik.svg' },
|
|
oidc: { label: 'OIDC', file: 'oidc.svg' }
|
|
};
|
|
|
|
// Generic fallback for unknown providers
|
|
const GENERIC_PROVIDER_ICON = 'oidc.svg';
|
|
|
|
interface OAuthButtonsProps {
|
|
onProviderClick: (provider: OAuthProvider) => void
|
|
isSubmitting: boolean
|
|
layout?: 'vertical' | 'grid' | 'icons'
|
|
enabledProviders?: OAuthProvider[] // List of enabled provider IDs from backend
|
|
}
|
|
|
|
export default function OAuthButtons({ onProviderClick, isSubmitting, layout = 'vertical', enabledProviders = [] }: OAuthButtonsProps) {
|
|
const { t } = useTranslation();
|
|
|
|
// Debug mode: show all providers for UI testing
|
|
const providersToShow = DEBUG_SHOW_ALL_PROVIDERS
|
|
? Object.keys(oauthProviderConfig)
|
|
: enabledProviders;
|
|
|
|
// Build provider list - use provider ID to determine icon and label
|
|
const providers = providersToShow.map(id => {
|
|
if (id in oauthProviderConfig) {
|
|
// Known provider - use predefined icon and label
|
|
return {
|
|
id,
|
|
...oauthProviderConfig[id]
|
|
};
|
|
}
|
|
// Unknown provider - use generic icon and capitalize ID for label
|
|
return {
|
|
id,
|
|
label: id.charAt(0).toUpperCase() + id.slice(1),
|
|
file: GENERIC_PROVIDER_ICON
|
|
};
|
|
});
|
|
|
|
// If no providers are enabled, don't render anything
|
|
if (providers.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
if (layout === 'icons') {
|
|
return (
|
|
<div className="oauth-container-icons">
|
|
{providers.map((p) => (
|
|
<div key={p.id} title={`${t('login.signInWith', 'Sign in with')} ${p.label}`}>
|
|
<button
|
|
onClick={() => onProviderClick(p.id)}
|
|
disabled={isSubmitting}
|
|
className="oauth-button-icon"
|
|
aria-label={`${t('login.signInWith', 'Sign in with')} ${p.label}`}
|
|
>
|
|
<img src={`${BASE_PATH}/Login/${p.file}`} alt={p.label} className="oauth-icon-small"/>
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (layout === 'grid') {
|
|
return (
|
|
<div className="oauth-container-grid">
|
|
{providers.map((p) => (
|
|
<div key={p.id} title={`${t('login.signInWith', 'Sign in with')} ${p.label}`}>
|
|
<button
|
|
onClick={() => onProviderClick(p.id)}
|
|
disabled={isSubmitting}
|
|
className="oauth-button-grid"
|
|
aria-label={`${t('login.signInWith', 'Sign in with')} ${p.label}`}
|
|
>
|
|
<img src={`${BASE_PATH}/Login/${p.file}`} alt={p.label} className="oauth-icon-medium"/>
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="oauth-container-vertical">
|
|
{providers.map((p) => (
|
|
<button
|
|
key={p.id}
|
|
onClick={() => onProviderClick(p.id)}
|
|
disabled={isSubmitting}
|
|
className="oauth-button-vertical"
|
|
title={p.label}
|
|
>
|
|
<img src={`${BASE_PATH}/Login/${p.file}`} alt={p.label} className="oauth-icon-tiny" />
|
|
{p.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|