fix: prevent logout loop by showing signed-out state instead of auto-redirecting
After logout, redirect to /platform/login?signed_out which shows a "Signed out" card with a "Sign in again" button instead of immediately redirecting back to Logto OIDC (which would auto-authenticate if the Logto session cookie persists). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,20 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useLogto } from '@logto/react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Spinner } from '@cameleer/design-system';
|
||||
import { Button, Card, Spinner } from '@cameleer/design-system';
|
||||
import cameleerLogo from '@cameleer/design-system/assets/cameleer-logo.svg';
|
||||
|
||||
export function LoginPage() {
|
||||
const { signIn, isAuthenticated, isLoading } = useLogto();
|
||||
const navigate = useNavigate();
|
||||
const redirected = useRef(false);
|
||||
|
||||
// Check if we arrived here from a logout redirect
|
||||
const [signedOut] = useState(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.has('signed_out');
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
navigate('/', { replace: true });
|
||||
@@ -15,11 +22,39 @@ export function LoginPage() {
|
||||
}, [isAuthenticated, navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
// Don't auto-redirect after logout — show the signed-out state instead
|
||||
if (signedOut) return;
|
||||
if (!isLoading && !isAuthenticated && !redirected.current) {
|
||||
redirected.current = true;
|
||||
signIn(`${window.location.origin}/platform/callback`);
|
||||
}
|
||||
}, [isLoading, isAuthenticated, signIn]);
|
||||
}, [isLoading, isAuthenticated, signIn, signedOut]);
|
||||
|
||||
if (signedOut && !isAuthenticated) {
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' }}>
|
||||
<div style={{ maxWidth: 360, textAlign: 'center' }}>
|
||||
<Card>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16 }}>
|
||||
<img src={cameleerLogo} alt="" width="48" height="48" />
|
||||
<h2 style={{ margin: 0, fontSize: '1.25rem', fontWeight: 600 }}>Signed out</h2>
|
||||
<p style={{ margin: 0, color: 'var(--text-secondary)', fontSize: '0.875rem' }}>
|
||||
You have been signed out successfully.
|
||||
</p>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
window.location.href = window.location.origin + '/platform/login';
|
||||
}}
|
||||
>
|
||||
Sign in again
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' }}>
|
||||
|
||||
@@ -7,7 +7,7 @@ export function useAuth() {
|
||||
const { currentTenantId } = useOrgStore();
|
||||
|
||||
const logout = useCallback(() => {
|
||||
signOut(window.location.origin + '/platform/login');
|
||||
signOut(window.location.origin + '/platform/login?signed_out');
|
||||
}, [signOut]);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user