books/frontend/src/components/auth/ProtectedRoute.tsx
Nicolaj Hartmann 926085eeab Add OpenID Connect + API Key authentication
Backend:
- Cookie + OIDC + API Key authentication schemes
- ApiKeyAuthenticationHandler with SHA-256 validation and 24h cache
- AuthController with login/logout/profile endpoints
- API Key domain model (EventFlow aggregate, events, commands)
- ApiKeyReadModel and repository for key validation
- Database migration 002_ApiKeys.sql
- CORS configuration for frontend

Frontend:
- authService.ts for login/logout/profile API calls
- authStore.ts (Zustand) for user context state
- ProtectedRoute component for route guards
- Header updated with user display and logout
- GraphQL client with credentials: include

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 11:49:29 +01:00

64 lines
1.5 KiB
TypeScript

import { useEffect, type ReactNode } from 'react';
import { Spin } from 'antd';
import { useAuthStore } from '@/stores/authStore';
interface ProtectedRouteProps {
children: ReactNode;
}
/**
* Wrapper component that ensures the user is authenticated
* Shows loading spinner while checking auth status
* Redirects to login if not authenticated
*/
export function ProtectedRoute({ children }: ProtectedRouteProps) {
const { isAuthenticated, isLoading, login, refreshUser } = useAuthStore();
// Check auth on mount
useEffect(() => {
refreshUser();
}, [refreshUser]);
// Show loading spinner while checking auth
if (isLoading) {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
flexDirection: 'column',
gap: 16,
}}
>
<Spin size="large" />
<span style={{ color: '#666' }}>Logger ind...</span>
</div>
);
}
// Redirect to login if not authenticated
if (!isAuthenticated) {
login();
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
flexDirection: 'column',
gap: 16,
}}
>
<Spin size="large" />
<span style={{ color: '#666' }}>Omdirigerer til login...</span>
</div>
);
}
return <>{children}</>;
}
export default ProtectedRoute;