diff --git a/ui/src/auth/LoginPage.tsx b/ui/src/auth/LoginPage.tsx
index 17df6779..63609aed 100644
--- a/ui/src/auth/LoginPage.tsx
+++ b/ui/src/auth/LoginPage.tsx
@@ -47,11 +47,43 @@ export function LoginPage() {
const [password, setPassword] = useState('');
const [oidcLoading, setOidcLoading] = useState(false);
+ // Mirrors cameleer-saas: when logout sets this flag, render a "Signed out"
+ // confirmation instead of the regular form. The flag is one-shot — read +
+ // cleared on mount.
+ const [signedOut] = useState(() => {
+ const flag = sessionStorage.getItem('cameleer:signed_out');
+ if (flag) sessionStorage.removeItem('cameleer:signed_out');
+ return !!flag;
+ });
+
const { data: caps, isError: capsFailed, isLoading: capsLoading } = useAuthCapabilities();
if (isAuthenticated) return ;
if (capsLoading) return null;
+ if (signedOut) {
+ return (
+
+
+
+
+

+ cameleer
+
+
You have been signed out successfully.
+
+
+
+
+ );
+ }
+
const oidcPrimary = caps?.oidc?.primary === true;
const adminRecoveryOnly = caps?.localAccounts?.adminRecoveryOnly === true;
const providerName = caps?.oidc?.providerName || 'Single Sign-On';
@@ -87,10 +119,13 @@ export function LoginPage() {
client_id: data.clientId,
redirect_uri: redirectUri,
scope: scopes.join(' '),
+ // Defence-in-depth: even if RP-Initiated Logout did not fully clear
+ // the IdP session (proxy/cookie edge cases), prompt=login forces the
+ // IdP to re-prompt for credentials instead of silent re-auth.
+ // OIDC Core 1.0 §3.1.2.1.
+ prompt: 'login',
});
if (data.resource) params.set('resource', data.resource);
- // Note: NO prompt=none. Per RFC 9700 §4.4, that's silent re-auth only;
- // for first-time login it returns login_required and traps users on a local form.
window.location.href = `${data.authorizationEndpoint}?${params}`;
} catch {
useAuthStore.setState({ error: 'OIDC configuration unavailable. Try the local form via /login?local.' });