Skip to main content
Glama
AuthContext.tsx4.81 kB
import React, { createContext, useState, useContext, useEffect, useCallback } from 'react'; import type { ReactNode } from 'react'; import { fetchWithAuth } from '../utils/api'; interface User { sub: string; username?: string; grupos: string[]; papel: string; exp: number; } interface AuthContextType { token: string | null; user: User | null; isAuthenticated: boolean; isLoading: boolean; login: (token: string) => void; logout: () => void; refreshToken: () => Promise<boolean>; } const AuthContext = createContext<AuthContextType | undefined>(undefined); // Função para decodificar o payload do JWT function parseJwt(token: string): User | null { try { return JSON.parse(atob(token.split('.')[1])); } catch { return null; } } // Função para verificar se um token está expirado function isTokenExpired(token: string): boolean { try { const decoded = parseJwt(token); if (!decoded || !decoded.exp) return true; // Adiciona margem de segurança (30 segundos) para evitar que o token expire durante a requisição return decoded.exp * 1000 < Date.now() + 30000; } catch { return true; } } export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [token, setToken] = useState<string | null>(() => { const storedToken = localStorage.getItem('mcp_token'); if (storedToken && isTokenExpired(storedToken)) { localStorage.removeItem('mcp_token'); return null; } return storedToken; }); const [user, setUser] = useState<User | null>(null); const [isLoading, setIsLoading] = useState<boolean>(true); // Computar isAuthenticated com base nos valores de token e user const isAuthenticated = Boolean(token && user); // Função para atualizar o token const refreshToken = useCallback(async (): Promise<boolean> => { if (!token) return false; try { setIsLoading(true); const response = await fetchWithAuth('/tools/refresh-token', token); if (!response.ok) { // Se token expirou, limpar sessão do usuário if (response.status === 401) { localStorage.removeItem('mcp_token'); setToken(null); setUser(null); } console.error('Erro ao renovar token:', response.status); return false; } const data = await response.json(); const newToken = data.access_token; const tokenValue = newToken.startsWith('Bearer ') ? newToken.substring(7) : newToken; localStorage.setItem('mcp_token', tokenValue); setToken(tokenValue); const userData = parseJwt(tokenValue); if (userData) { setUser(userData); return true; } return false; } catch (error) { console.error('Erro inesperado ao renovar token:', error); return false; } finally { setIsLoading(false); } }, [token]); useEffect(() => { setIsLoading(true); if (!token) { setUser(null); setIsLoading(false); return; } try { const decodedUser = parseJwt(token); if (decodedUser) { if (decodedUser.exp * 1000 > Date.now()) { setUser(decodedUser); } else { console.warn('Token expirado. Limpando sessão.'); localStorage.removeItem('mcp_token'); setToken(null); setUser(null); } } else { console.warn('Token inválido. Limpando sessão.'); localStorage.removeItem('mcp_token'); setToken(null); setUser(null); } } catch (error) { console.error('Erro ao processar token:', error); localStorage.removeItem('mcp_token'); setToken(null); setUser(null); } finally { setIsLoading(false); } }, [token]); const login = (newToken: string) => { const tokenValue = newToken.startsWith('Bearer ') ? newToken.substring(7) : newToken; localStorage.setItem('mcp_token', tokenValue); setToken(tokenValue); const userData = parseJwt(tokenValue); if (userData) { setUser(userData); } else { console.error('Falha ao decodificar token durante login'); } }; const logout = () => { localStorage.removeItem('mcp_token'); setToken(null); setUser(null); }; return ( <AuthContext.Provider value={{ token, user, isAuthenticated, isLoading, login, logout, refreshToken }}> {children} </AuthContext.Provider> ); }; export const useAuth = (): AuthContextType => { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; };

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/jowpereira/mcp-server'

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