Skip to main content
Glama
AuthContext.tsx4.75 kB
"use client"; import { useCallback, useEffect, useMemo, useState, type ReactNode, } from "react"; import { getAuthBffUrl, isEnterpriseEnabled } from "@/config/runtime-config"; import { AuthContext } from "./auth-internal"; import { AuthContextValue, AuthState } from "./auth-types"; export type { AuthUser, AuthState, AuthContextValue } from "./auth-types"; function normalizeBaseUrl(url: string | null): string | null { if (!url) return null; return url.endsWith("/") ? url.slice(0, -1) : url; } export function AuthProvider({ children }: { children: ReactNode }) { const loginRequired = useMemo(() => isEnterpriseEnabled(), []); const rawAuthBffUrl = getAuthBffUrl(); const authBffBase = useMemo( () => normalizeBaseUrl(rawAuthBffUrl), [rawAuthBffUrl], ); const [state, setState] = useState<AuthState>(() => ({ user: null, isAuthenticated: !loginRequired, loading: loginRequired, error: loginRequired && !authBffBase ? "Enterprise login is enabled but VITE_AUTH_BFF_URL is not configured." : null, })); const buildAuthBffUrl = useCallback( (path: string) => { if (!authBffBase) { return path; } return `${authBffBase}${path}`; }, [authBffBase], ); const checkAuthStatus = useCallback(async () => { if (!loginRequired) { setState({ user: null, isAuthenticated: true, loading: false, error: null, }); return; } if (!authBffBase) { setState({ user: null, isAuthenticated: false, loading: false, error: "Enterprise login is enabled but VITE_AUTH_BFF_URL is not configured.", }); return; } setState((prev) => ({ ...prev, loading: true, error: null, })); try { const response = await fetch(buildAuthBffUrl("/me"), { method: "GET", credentials: "include", mode: "cors", }); if (response.ok) { const data = await response.json(); setState({ user: data.user ?? null, isAuthenticated: true, loading: false, error: null, }); return; } if (response.status === 401) { setState({ user: null, isAuthenticated: false, loading: false, error: null, }); return; } const message = (await response.text()) || "Authentication check failed. Please try again."; setState({ user: null, isAuthenticated: false, loading: false, error: message, }); } catch (error) { setState({ user: null, isAuthenticated: false, loading: false, error: error instanceof Error ? error.message : "Authentication check failed. Please try again.", }); } }, [authBffBase, buildAuthBffUrl, loginRequired]); useEffect(() => { if (!loginRequired) { setState({ user: null, isAuthenticated: true, loading: false, error: null, }); return; } checkAuthStatus(); }, [checkAuthStatus, loginRequired]); const login = useCallback( (redirectUri?: string) => { if (!loginRequired || !authBffBase) { console.error( "Enterprise login is enabled but auth BFF URL is not configured.", ); return; } if (typeof window === "undefined") return; const target = redirectUri || window.location.href; const loginUrl = `${buildAuthBffUrl( "/login", )}?redirect_uri=${encodeURIComponent(target)}`; window.location.href = loginUrl; }, [authBffBase, buildAuthBffUrl, loginRequired], ); const logout = useCallback(() => { if (!loginRequired || !authBffBase) { if (typeof window !== "undefined") { window.location.reload(); } return; } if (typeof window === "undefined") return; const target = window.location.href; const logoutUrl = `${buildAuthBffUrl("/logout")}?redirect_uri=${encodeURIComponent(target)}`; window.location.href = logoutUrl; }, [authBffBase, buildAuthBffUrl, loginRequired]); const refresh = useCallback(async () => { if (!loginRequired || !authBffBase) { return; } await checkAuthStatus(); }, [authBffBase, checkAuthStatus, loginRequired]); const stableValue = useMemo( () => ({ loginRequired, login, logout, refresh }), [loginRequired, login, logout, refresh], ); const value: AuthContextValue = { ...state, ...stableValue }; return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; }

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/TheLunarCompany/lunar'

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