Careeroza
Logout
Logging Out with JWTs
With stateless JWTs, "logout" on the client means forgetting the token. The token itself stays valid until it expires, which is another reason to keep access tokens short-lived. The Refresh Tokens module adds a server-side logout that revokes the refresh token.
// src/components/Navbar.jsx
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../auth/AuthContext';
export default function Navbar() {
const { user, logout, hasRole } = useAuth();
const navigate = useNavigate();
function handleLogout() {
logout();
navigate('/login', { replace: true });
}
return (
<nav>
<Link to="/">ShopEase</Link>
{hasRole('ROLE_SELLER') && <Link to="/seller">Seller dashboard</Link>}
{hasRole('ROLE_ADMIN') && <Link to="/admin">Admin</Link>}
{user ? (
<>
<span>Hi, {user.email}</span>
<button onClick={handleLogout}>Logout</button>
</>
) : (
<Link to="/login">Login</Link>
)}
</nav>
);
}Logout in Every Tab
If the user has ShopEase open in two tabs, logging out in one should log out the other. The browser fires a storage event in other tabs when localStorage changes:
// inside AuthProvider
useEffect(() => {
function onStorage(e) {
if (e.key === 'shopease_token' && e.newValue === null) setUser(null);
}
window.addEventListener('storage', onStorage);
return () => window.removeEventListener('storage', onStorage);
}, []);Exercise
Exercise: Show a message "Your session expired, please log in again" on the login page when the user was redirected by the 401 interceptor (it adds ?expired=1).
Show answer
import { useSearchParams } from 'react-router-dom';
export default function LoginPage() {
const [params] = useSearchParams();
const expired = params.get('expired') === '1';
// ...
return (
<form onSubmit={handleSubmit}>
{expired && <p className="info">Your session expired, please log in again</p>}
{/* inputs and button as before */}
</form>
);
}