AeThex-OS/client/src/lib/auth.tsx
sirpiglr 8ee5f71ef4 Add login, admin panel, and user management features
Introduces authentication via JWT, session management with CSRF protection, and new admin routes for managing users, projects, and monitoring security. Enhances dashboard and home pages with dynamic metrics fetched from the backend.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 279f1558-c0e3-40e4-8217-be7e9f4c6eca
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: dcd55177-c240-4288-8fc0-652032c758f2
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/b984cb14-1d19-4944-922b-bc79e821ed35/279f1558-c0e3-40e4-8217-be7e9f4c6eca/2riq6Ir
Replit-Helium-Checkpoint-Created: true
2025-12-15 22:15:36 +00:00

89 lines
2.3 KiB
TypeScript

import { createContext, useContext, useState, useEffect, ReactNode } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
interface User {
id: string;
username: string;
isAdmin: boolean;
}
interface AuthContextType {
user: User | null;
isLoading: boolean;
isAuthenticated: boolean;
isAdmin: boolean;
login: (username: string, password: string) => Promise<void>;
logout: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const queryClient = useQueryClient();
const { data: session, isLoading } = useQuery({
queryKey: ["session"],
queryFn: async () => {
const res = await fetch("/api/auth/session");
return res.json();
},
});
const loginMutation = useMutation({
mutationFn: async ({ username, password }: { username: string; password: string }) => {
const res = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
if (!res.ok) {
const data = await res.json();
throw new Error(data.error || "Login failed");
}
return res.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["session"] });
},
});
const logoutMutation = useMutation({
mutationFn: async () => {
await fetch("/api/auth/logout", { method: "POST" });
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["session"] });
},
});
const login = async (username: string, password: string) => {
await loginMutation.mutateAsync({ username, password });
};
const logout = async () => {
await logoutMutation.mutateAsync();
};
const value: AuthContextType = {
user: session?.authenticated ? session.user : null,
isLoading,
isAuthenticated: !!session?.authenticated,
isAdmin: session?.user?.isAdmin || false,
login,
logout,
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}