import { useEffect, useRef } from 'react'; import { Navigate, useNavigate } from 'react-router'; import { useAuthStore } from './auth-store'; import { api } from '../api/client'; import { Card, Spinner, Alert, Button } from '@cameleer/design-system'; import { config } from '../config'; import styles from './OidcCallback.module.css'; export function OidcCallback() { const { isAuthenticated, loading, error, loginWithOidcCode } = useAuthStore(); const navigate = useNavigate(); const exchanged = useRef(false); useEffect(() => { if (exchanged.current) return; exchanged.current = true; const params = new URLSearchParams(window.location.search); const code = params.get('code'); const errorParam = params.get('error'); if (errorParam) { // prompt=none failed — no session, fall back to login form if (errorParam === 'login_required' || errorParam === 'interaction_required') { window.location.replace(`${config.basePath}login?local`); return; } // consent_required — retry without prompt=none so user can grant scopes if (errorParam === 'consent_required' && !sessionStorage.getItem('oidc-consent-retry')) { sessionStorage.setItem('oidc-consent-retry', '1'); api.GET('/auth/oidc/config').then(({ data }) => { if (data?.authorizationEndpoint && data?.clientId) { const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`; const PLATFORM_SCOPES = ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles']; const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(data.additionalScopes || [])]; const p = new URLSearchParams({ response_type: 'code', client_id: data.clientId, redirect_uri: redirectUri, scope: scopes.join(' '), }); if (data.resource) p.set('resource', data.resource); window.location.href = `${data.authorizationEndpoint}?${p}`; } }).catch(() => { window.location.replace(`${config.basePath}login?local`); }); return; } sessionStorage.removeItem('oidc-consent-retry'); useAuthStore.setState({ error: params.get('error_description') || errorParam, loading: false, }); return; } sessionStorage.removeItem('oidc-consent-retry'); if (!code) { useAuthStore.setState({ error: 'No authorization code received', loading: false }); return; } const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`; loginWithOidcCode(code, redirectUri); }, [loginWithOidcCode]); if (isAuthenticated) return ; return (

cameleer

{loading && } {error && ( <> {error} )}
); }