llama-stack-mirror/llama_stack/ui/contexts/auth-context.tsx
Eric Huang a4d84f7805 ui
# What does this PR do?


## Test Plan
# What does this PR do?


## Test Plan
# What does this PR do?


## Test Plan
2025-06-25 20:10:46 -07:00

115 lines
2.7 KiB
TypeScript

"use client";
import React, {
createContext,
useContext,
useState,
useEffect,
useCallback,
} from "react";
import { useRouter } from "next/navigation";
import {
User,
getAuthToken,
setAuthToken,
getStoredUser,
setStoredUser,
clearAuth,
isTokenExpired,
} from "@/lib/auth";
interface AuthContextType {
user: User | null;
isLoading: boolean;
isAuthenticated: boolean;
login: (token: string) => Promise<void>;
logout: () => void;
checkAuth: () => void;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
const checkAuth = useCallback(() => {
const token = getAuthToken();
const storedUser = getStoredUser();
if (token && storedUser && !isTokenExpired(token)) {
setUser(storedUser);
} else {
clearAuth();
setUser(null);
}
setIsLoading(false);
}, []);
useEffect(() => {
checkAuth();
}, [checkAuth]);
const login = useCallback(
async (token: string) => {
try {
// Decode JWT to get user info
const base64Url = token.split(".")[1];
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
const jsonPayload = decodeURIComponent(
atob(base64)
.split("")
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
.join(""),
);
const claims = JSON.parse(jsonPayload);
// Extract user info from JWT claims
const userInfo: User = {
username: claims.github_username || claims.sub,
email: claims.email,
name: claims.name,
avatar_url: claims.avatar_url,
organizations: claims.github_orgs,
};
setAuthToken(token);
setStoredUser(userInfo);
setUser(userInfo);
router.push("/"); // Redirect to home after login
} catch (error) {
// Clear token if we can't decode it
clearAuth();
throw new Error("Failed to decode authentication token");
}
},
[router],
);
const logout = useCallback(() => {
clearAuth();
setUser(null);
router.push("/login");
}, [router]);
const value = {
user,
isLoading,
isAuthenticated: !!user,
login,
logout,
checkAuth,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}