Skip to main content
Glama
ProtectedRoute.tsx4.34 kB
import type { ReactNode } from 'react'; import { useEffect, useState } from 'react'; import { Navigate, useLocation } from 'react-router-dom'; import axios from 'axios'; const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:3000'; interface AdminUser { id: string; username: string; email?: string; display_name?: string; role: string; } interface ProtectedRouteProps { children: ReactNode; authEnabled: boolean; isAuthenticated: boolean; } export default function ProtectedRoute({ children, authEnabled, isAuthenticated }: ProtectedRouteProps) { const location = useLocation(); // If auth is disabled, allow access if (!authEnabled) { return <>{children}</>; } // If auth is enabled but not authenticated, redirect to login if (!isAuthenticated) { return <Navigate to="/login" state={{ from: location }} replace />; } // Authenticated, render children return <>{children}</>; } /** * Hook to check auth status */ export function useAuthStatus() { const [authEnabled, setAuthEnabled] = useState<boolean | null>(null); const [isAuthenticated, setIsAuthenticated] = useState(false); const [user, setUser] = useState<AdminUser | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { checkAuthStatus(); }, []); async function checkAuthStatus() { try { // Check if auth is enabled on server const statusRes = await axios.get(`${API_BASE}/v1/auth/status`); const enabled = statusRes.data.authEnabled; setAuthEnabled(enabled); if (!enabled) { // Auth disabled, no login needed setIsAuthenticated(true); setLoading(false); return; } // Auth enabled, check for stored token const token = localStorage.getItem('auth_token'); const storedUser = localStorage.getItem('auth_user'); if (!token) { setIsAuthenticated(false); setLoading(false); return; } // Verify token is still valid try { const verifyRes = await axios.post(`${API_BASE}/v1/auth/verify`, { token }); if (verifyRes.data.valid) { setIsAuthenticated(true); setUser(verifyRes.data.user || (storedUser ? JSON.parse(storedUser) : null)); } else { // Token invalid, clear storage localStorage.removeItem('auth_token'); localStorage.removeItem('auth_user'); setIsAuthenticated(false); } } catch { // Token verification failed localStorage.removeItem('auth_token'); localStorage.removeItem('auth_user'); setIsAuthenticated(false); } } catch (error) { console.error('Failed to check auth status:', error); // Assume auth is disabled if server is unreachable setAuthEnabled(false); setIsAuthenticated(true); } finally { setLoading(false); } } function login(token: string, userData: AdminUser) { localStorage.setItem('auth_token', token); localStorage.setItem('auth_user', JSON.stringify(userData)); setIsAuthenticated(true); setUser(userData); } function logout() { localStorage.removeItem('auth_token'); localStorage.removeItem('auth_user'); setIsAuthenticated(false); setUser(null); } return { authEnabled, isAuthenticated, user, loading, login, logout, checkAuthStatus, }; } /** * Get auth token for API calls */ export function getAuthToken(): string | null { return localStorage.getItem('auth_token'); } /** * Create axios instance with auth header */ export function createAuthAxios() { const instance = axios.create({ baseURL: API_BASE, }); instance.interceptors.request.use((config) => { const token = getAuthToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); instance.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { // Token expired or invalid, clear storage localStorage.removeItem('auth_token'); localStorage.removeItem('auth_user'); // Optionally redirect to login window.location.href = '/login'; } return Promise.reject(error); } ); return instance; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babasida246/ai-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server