React SPA
A complete React SPA with cookie-based auth, protected routes, login page, and profile page.
-
Install packages
npm install authfort-client react-router-domnpm install authfort-client react-router-dom -
Create the auth client
src/auth.tsimport { createAuthClient } from 'authfort-client'; export const auth = createAuthClient({ baseUrl: '/auth', tokenMode: 'cookie', });import { createAuthClient } from 'authfort-client'; export const auth = createAuthClient({ baseUrl: '/auth', tokenMode: 'cookie', }); -
Wrap your app with AuthProvider
src/main.tsximport { AuthProvider } from 'authfort-client/react'; import { BrowserRouter } from 'react-router-dom'; import { auth } from './auth'; import App from './App'; auth.initialize(); ReactDOM.createRoot(document.getElementById('root')!).render( <BrowserRouter> <AuthProvider client={auth}> <App /> </AuthProvider> </BrowserRouter> );import { AuthProvider } from 'authfort-client/react'; import { BrowserRouter } from 'react-router-dom'; import { auth } from './auth'; import App from './App'; auth.initialize(); ReactDOM.createRoot(document.getElementById('root')!).render( <BrowserRouter> <AuthProvider client={auth}> <App /> </AuthProvider> </BrowserRouter> );
Protected Route Component
Section titled “Protected Route Component” src/components/ProtectedRoute.tsx
import { useAuth } from 'authfort-client/react';
import { Navigate } from 'react-router-dom';
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <Navigate to="/login" replace />;
return children;
} import { useAuth } from 'authfort-client/react';
import { Navigate } from 'react-router-dom';
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <Navigate to="/login" replace />;
return children;
} Login Page
Section titled “Login Page” src/pages/Login.tsx
import { useState } from 'react';
import { useAuth } from 'authfort-client/react';
import { useNavigate } from 'react-router-dom';
export function LoginPage() {
const { client } = useAuth();
const navigate = useNavigate();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
await client.signIn({ email, password });
navigate('/');
} catch (err: any) {
setError(err.message);
}
};
return (
<form onSubmit={handleSubmit}>
<h1>Sign In</h1>
<input
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign In</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
<hr />
<button type="button" onClick={() => client.signInWithProvider('google')}>
Sign in with Google
</button>
<button type="button" onClick={() => client.signInWithProvider('github')}>
Sign in with GitHub
</button>
</form>
);
} import { useState } from 'react';
import { useAuth } from 'authfort-client/react';
import { useNavigate } from 'react-router-dom';
export function LoginPage() {
const { client } = useAuth();
const navigate = useNavigate();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
await client.signIn({ email, password });
navigate('/');
} catch (err: any) {
setError(err.message);
}
};
return (
<form onSubmit={handleSubmit}>
<h1>Sign In</h1>
<input
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign In</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
<hr />
<button type="button" onClick={() => client.signInWithProvider('google')}>
Sign in with Google
</button>
<button type="button" onClick={() => client.signInWithProvider('github')}>
Sign in with GitHub
</button>
</form>
);
} Profile Page
Section titled “Profile Page” src/pages/Profile.tsx
import { useAuth } from 'authfort-client/react';
export function ProfilePage() {
const { user, client } = useAuth();
return (
<div>
<h1>Profile</h1>
<p>Email: {user?.email}</p>
<p>Name: {user?.name}</p>
<p>Roles: {user?.roles.join(', ') || 'none'}</p>
<button onClick={() => client.signOut()}>Sign Out</button>
</div>
);
} import { useAuth } from 'authfort-client/react';
export function ProfilePage() {
const { user, client } = useAuth();
return (
<div>
<h1>Profile</h1>
<p>Email: {user?.email}</p>
<p>Name: {user?.name}</p>
<p>Roles: {user?.roles.join(', ') || 'none'}</p>
<button onClick={() => client.signOut()}>Sign Out</button>
</div>
);
} App Routes
Section titled “App Routes” src/App.tsx
import { Routes, Route } from 'react-router-dom';
import { ProtectedRoute } from './components/ProtectedRoute';
import { LoginPage } from './pages/Login';
import { ProfilePage } from './pages/Profile';
export default function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={
<ProtectedRoute>
<ProfilePage />
</ProtectedRoute>
} />
</Routes>
);
} import { Routes, Route } from 'react-router-dom';
import { ProtectedRoute } from './components/ProtectedRoute';
import { LoginPage } from './pages/Login';
import { ProfilePage } from './pages/Profile';
export default function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={
<ProtectedRoute>
<ProfilePage />
</ProtectedRoute>
} />
</Routes>
);
} Fetching Data
Section titled “Fetching Data”import { useAuth } from 'authfort-client/react';
import { useEffect, useState } from 'react';
function Orders() {
const { client } = useAuth();
const [orders, setOrders] = useState([]);
useEffect(() => {
client.fetch('/api/orders')
.then(res => res.json())
.then(setOrders);
}, [client]);
return (
<ul>
{orders.map((o: any) => <li key={o.id}>{o.name}</li>)}
</ul>
);
} import { useAuth } from 'authfort-client/react';
import { useEffect, useState } from 'react';
function Orders() {
const { client } = useAuth();
const [orders, setOrders] = useState([]);
useEffect(() => {
client.fetch('/api/orders')
.then(res => res.json())
.then(setOrders);
}, [client]);
return (
<ul>
{orders.map((o: any) => <li key={o.id}>{o.name}</li>)}
</ul>
);
}