Por que e como implementar refresh token
ResumoTokens de acesso (JWT) devem ter vida curta por segurança, mas pedir login a cada 15 minutos é ruim. O refresh token renova o acesso sem novas credenciais, com armazenamento e rotação seguros.
1. Objetivos de Aprendizagem#
- Explicar por que separar access token e refresh token.
- Emitir e persistir o refresh token no usuário.
- Implementar o endpoint de renovação com rotação.
2. Pré-requisitos#
- JWT e autenticação (Módulo 40).
3. Conceito#
- Access token (JWT): curto (ex.: 15 min), stateless, enviado em toda requisição.
- Refresh token: longo (ex.: 7 dias), opaco, guardado no servidor, usado só para obter um novo access token.
O porquê: se o access token vazar, expira rápido; o refresh token, guardado e revogável, permite invalidar sessões. A rotação (emitir um novo refresh a cada uso e invalidar o anterior) detecta reuso indevido.
Fluxo de renovação com rotação:
4. Mão na Massa#
4.1. Setup#
Adicione campos ao ApplicationUser:
public class ApplicationUser : IdentityUser
{
public string? RefreshToken { get; set; }
public DateTime RefreshTokenExpiryTime { get; set; }
}
Gere a migration correspondente.
4.2. Implementação Passo a Passo#
- Gerar refresh token aleatório e seguro:
private static string GenerateRefreshToken()
{
var bytes = new byte[64];
using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
rng.GetBytes(bytes);
return Convert.ToBase64String(bytes);
}
- No login, emitir os dois e persistir o refresh:
var accessToken = CreateToken(user, roles);
var refreshToken = GenerateRefreshToken();
user.RefreshToken = refreshToken;
user.RefreshTokenExpiryTime = DateTime.UtcNow.AddDays(7);
await _userManager.UpdateAsync(user);
return new TokenDto(accessToken, refreshToken);
- Endpoint de renovação com validação e rotação:
public async Task<TokenDto> RefreshAsync(TokenDto tokenDto)
{
var principal = GetPrincipalFromExpiredToken(tokenDto.AccessToken);
var user = await _userManager.FindByNameAsync(principal.Identity!.Name!);
if (user is null ||
user.RefreshToken != tokenDto.RefreshToken ||
user.RefreshTokenExpiryTime <= DateTime.UtcNow)
throw new RefreshTokenBadRequestException();
var roles = await _userManager.GetRolesAsync(user);
var newAccess = CreateToken(user, roles);
var newRefresh = GenerateRefreshToken(); // rotação
user.RefreshToken = newRefresh;
await _userManager.UpdateAsync(user);
return new TokenDto(newAccess, newRefresh);
}
GetPrincipalFromExpiredToken valida a assinatura com ValidateLifetime = false.
4.3. Executando#
curl -X POST http://localhost:5000/api/token/refresh \
-H "Content-Type: application/json" \
-d '{"accessToken":"<expirado>","refreshToken":"<refresh>"}'
5. Exemplo Completo#
Fluxo: login → (access + refresh). Access expira → cliente chama /token/refresh → recebe novos tokens (refresh rotacionado). Logout → limpar RefreshToken do usuário.
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
| Gerar refresh com RNG criptográfico | Guid/Random como refresh token |
| Rotacionar o refresh a cada uso | Reutilizar o mesmo refresh indefinidamente |
| Validar assinatura mesmo no token expirado | Desligar toda validação para "ler" o token |
Atençãoao renovar, valide a assinatura do access token expirado (só
ValidateLifetime = false). Nunca aceite qualquer token sem verificar a assinatura.
7. Segurança e Produção#
- Refresh tokens são credenciais de longa duração: armazene com cuidado e permita revogação (logout, troca de senha).
- Detecte reuso de refresh já rotacionado como possível roubo e invalide toda a cadeia.
- Sempre HTTPS.
8. Exercícios#
- Fácil: implemente logout limpando o
RefreshToken. - Médio: invalide todos os refresh tokens ao trocar a senha.
- Desafio: implemente detecção de reuso (refresh já usado → revoga a sessão).
9. Resumo#
Access tokens curtos + refresh tokens longos e rotacionados equilibram segurança e experiência. Refresh é gerado com RNG seguro, persistido, revogável e sempre trafega sob HTTPS.
10. Próximos Passos#
Módulo 13: binding de configuração e Options Pattern.
11. Referências#
- Microsoft Learn — Autenticação JWT Bearer
- Microsoft Learn — RandomNumberGenerator
- OWASP — JWT / Token Cheat Sheet