Exemplo de Implementação de Refresh no Frontend
JavaScript/TypeScript
class AuthService {
private token: string | null = null;
private refreshTimer: NodeJS.Timeout | null = null;
constructor() {
this.token = localStorage.getItem('token');
this.startRefreshTimer();
}
// Método para fazer refresh do token
async refreshToken(): Promise<boolean> {
try {
const response = await fetch('/seguranca/autenticacao/token/refresh', {
method: 'GET',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
this.token = data.token;
localStorage.setItem('token', data.token);
// Reiniciar o timer de refresh
this.startRefreshTimer();
return true;
} else {
// Token inválido ou expirado
this.logout();
return false;
}
} catch (error) {
console.error('Erro ao renovar token:', error);
this.logout();
return false;
}
}
// Timer para refresh automático (a cada 50 minutos)
private startRefreshTimer() {
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
}
this.refreshTimer = setTimeout(() => {
this.refreshToken();
}, 50 * 60 * 1000); // 50 minutos
}
// Interceptor para requisições HTTP
async makeRequest(url: string, options: RequestInit = {}): Promise<Response> {
const headers = {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
...options.headers
};
let response = await fetch(url, { ...options, headers });
// Se receber 401, tentar refresh e refazer a requisição
if (response.status === 401) {
const refreshed = await this.refreshToken();
if (refreshed) {
headers['Authorization'] = `Bearer ${this.token}`;
response = await fetch(url, { ...options, headers });
}
}
return response;
}
logout() {
this.token = null;
localStorage.removeItem('token');
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
}
// Redirecionar para login
window.location.href = '/login';
}
}
// Uso do serviço
const authService = new AuthService();
// Exemplo de uso em uma requisição
async function buscarProdutos() {
try {
const response = await authService.makeRequest('/api/produtos');
const produtos = await response.json();
return produtos;
} catch (error) {
console.error('Erro ao buscar produtos:', error);
}
}
React Hook
import { useState, useEffect, useCallback } from 'react';
export const useAuth = () => {
const [token, setToken] = useState<string | null>(localStorage.getItem('token'));
const [isRefreshing, setIsRefreshing] = useState(false);
const refreshToken = useCallback(async (): Promise<boolean> => {
if (!token || isRefreshing) return false;
setIsRefreshing(true);
try {
const response = await fetch('/seguranca/autenticacao/token/refresh', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
setToken(data.token);
localStorage.setItem('token', data.token);
return true;
} else {
logout();
return false;
}
} catch (error) {
console.error('Erro ao renovar token:', error);
logout();
return false;
} finally {
setIsRefreshing(false);
}
}, [token, isRefreshing]);
const logout = useCallback(() => {
setToken(null);
localStorage.removeItem('token');
}, []);
// Refresh automático a cada 50 minutos
useEffect(() => {
if (!token) return;
const interval = setInterval(() => {
refreshToken();
}, 50 * 60 * 1000);
return () => clearInterval(interval);
}, [token, refreshToken]);
return { token, refreshToken, logout, isRefreshing };
};
Axios Interceptor
import axios from 'axios';
const api = axios.create({
baseURL: '/api'
});
// Interceptor para adicionar token nas requisições
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Interceptor para tratar 401 e fazer refresh
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const response = await axios.get('/seguranca/autenticacao/token/refresh', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
const { token } = response.data;
localStorage.setItem('token', token);
// Refazer a requisição original
originalRequest.headers.Authorization = `Bearer ${token}`;
return api(originalRequest);
} catch (refreshError) {
// Refresh falhou, redirecionar para login
localStorage.removeItem('token');
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default api;
Considerações Importantes
-
Frequência do Refresh: Configure para renovar antes do token expirar (ex: 50 minutos para token de 1 hora)
-
Tratamento de Erros: Sempre trate erros de refresh e redirecione para login quando necessário
-
Estado de Loading: Mostre indicador de loading durante o refresh para melhor UX
-
Múltiplas Requisições: Evite múltiplos refreshes simultâneos usando flags de controle
-
Logout Automático: Implemente logout automático quando refresh falha
-
Permissões Atualizadas: Após refresh bem-sucedido, as permissões estarão atualizadas no novo token