import React, { useEffect, useRef, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { Box, CircularProgress, Typography, Alert, Button } from '@mui/material'; const LoginCallback: React.FC = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { login } = useAuth(); const [error, setError] = useState(''); const hasCalledLogin = useRef(false); useEffect(() => { if (hasCalledLogin.current) return; hasCalledLogin.current = true; const handleCallback = async () => { const code = searchParams.get('code'); const errorParam = searchParams.get('error'); if (errorParam) { setError(`Authentifizierungsfehler: ${errorParam}`); return; } if (!code) { setError('Kein Autorisierungscode erhalten'); return; } try { await login(code); // Navigate to the originally intended page, falling back to the dashboard. // Validate that the stored path is a safe internal path: must start with '/' // but must NOT start with '//' (protocol-relative redirect). const rawFrom = sessionStorage.getItem('auth_redirect_from'); const from = rawFrom && rawFrom.startsWith('/') && !rawFrom.startsWith('//') ? rawFrom : '/dashboard'; sessionStorage.removeItem('auth_redirect_from'); navigate(from, { replace: true }); } catch (err) { console.error('Login callback error:', err); const is429 = err && typeof err === 'object' && 'status' in err && (err as any).status === 429; setError( is429 ? 'Zu viele Anmeldeversuche. Bitte warten Sie einige Minuten und versuchen Sie es erneut.' : err instanceof Error ? err.message : 'Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut.' ); } }; handleCallback(); }, [searchParams, login, navigate]); if (error) { return ( {error} ); } return ( Anmeldung wird abgeschlossen... ); }; export default LoginCallback;