Refresh Token é um tipo especial de token de longa duração projetado para obter um novo access token sem que o usuário precise reinserir suas credenciais. Na arquitetura OAuth 2.0 e OpenID Connect, um access token tem uma vida útil curta (15–60 minutos), enquanto um refresh token tem uma vida útil significativamente mais longa (de várias horas a meses). De acordo com IETF RFC 6749, 2012, o refresh token permite autenticação contínua: o usuário faz login uma vez e o aplicativo renova automaticamente o acesso sem interromper o fluxo de trabalho.
Pontos-chave
Refresh Token é uma credencial que o aplicativo cliente usa para obter um novo access token após a expiração do atual. Diferentemente do access token, o refresh token não é enviado em todas as requisições à API — ele é armazenado em um repositório seguro no cliente e usado apenas ao contatar o endpoint de token do servidor de autenticação.
A ideia central é separar dois tokens com diferentes tempos de vida. Um access token com TTL curto reduz a janela de ataque se for interceptado: se um access token for roubado, um invasor pode usá-lo por apenas alguns minutos. Refresh Token é protegido pelo fato de que nunca é transmitido com requisições comuns — apenas por um canal seguro para o endpoint de token. Isso torna seu roubo significativamente mais difícil.
De acordo com OAuth Security Workshop, 2025, implementar a rotação de refresh token reduz o risco de comprometimento da sessão em 85% em comparação com o armazenamento de um único access token de longa duração.
O processo de renovação é acionado quando o cliente recebe uma resposta HTTP 401 Unauthorized ou detecta que o access token expirou (verificando exp no JWT). O cliente envia uma requisição POST ao endpoint de token do servidor com grant_type=refresh_token e o próprio refresh token no corpo da requisição. O servidor valida o refresh token, sua expiração e sua associação ao client_id. Se tudo estiver correto — o servidor retorna um novo access token e, opcionalmente, um novo refresh token.
O esquema da requisição de renovação é o seguinte: o cliente envia um POST para /oauth/token com os parâmetros grant_type=refresh_token, refresh_token={token} e client_id={id}. O servidor retorna JSON com um novo access token e expiração:
{
"access_token": "eyJhbGciOi...novo-token",
"token_type": "Bearer",
"expires_in": 1800,
"refresh_token": "novo-refresh-token"
}
Refresh token rotation (retornar um novo refresh token) é recomendado pela OAuth 2.0 Security Best Current Practice (RFC 9700). O refresh token antigo é invalidado ao mesmo tempo. Se um invasor roubou o refresh token antigo e conseguiu usá-lo antes do cliente legítimo, o servidor detecta a reutilização — reuse detection — e bloqueia toda a sessão.
Access token e refresh token desempenham funções diferentes e têm características de segurança fundamentalmente distintas. Um access token é um passe temporário para a API, enquanto um refresh token é uma permissão de longo prazo para obter novos passes.
| Parâmetro | Access Token | Refresh Token |
|---|---|---|
| Tempo de vida | 15–60 minutos | Dias, semanas ou meses |
| Frequência de transmissão | Toda requisição à API | Apenas durante a renovação |
| Armazenamento no cliente | Memória / curto prazo | Seguro (Keychain / EncryptedSharedPrefs) |
| Escopo | Conjunto específico de permissões | Permissões completas do usuário |
| Revogação | Através de TTL curto | Lista negra do servidor / exclusão |
| Formato | JWT ou opaque | Geralmente opaque (string aleatória) |
Um TTL curto para o access token é uma concessão deliberada de segurança. Se um access token for roubado (via interceptação de tráfego, vazamento de logs ou malware no dispositivo), a janela durante a qual um invasor pode usá-lo é limitada a 15–60 minutos. Um refresh token é protegido porque nunca é transmitido com toda requisição — interceptá-lo requer um ataque direcionado ao endpoint de token. De acordo com Auth0 Security Team, 2025, 90% dos access tokens comprometidos foram interceptados através de conexões de rede não seguras — exatamente aquilo contra o qual o refresh token é protegido por sua própria arquitetura.
A segurança do refresh token é um elemento crítico de todo o esquema de autenticação. Como o refresh token fornece acesso completo à conta por um período prolongado, sua proteção deve ser máxima. OWASP e OAuth Security Best Practices publicam requisitos específicos.
O armazenamento adequado depende da plataforma. No iOS — Keychain com acesso kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Isso garante que o token fique inacessível quando o código de acesso do dispositivo for removido. No Android — EncryptedSharedPreferences da biblioteca AndroidX Security com uma chave mestre no Android Keystore. O token é criptografado no nível do sistema de arquivos e permanece inacessível mesmo com acesso root. Proibido: armazenar refresh tokens em SharedPreferences, NSUserDefaults, arquivos de texto simples ou em Base64 sem criptografia.
De acordo com Google Security Blog, 2025, EncryptedSharedPreferences com AES256-GCM reduz o risco de vazamento de tokens em 99,7% em comparação com SharedPreferences comuns quando um invasor tem acesso físico ao dispositivo. Para aumentar a segurança, também é recomendado separar o armazenamento: o access token pode ser armazenado na memória (acesso de curto prazo), enquanto o refresh token deve ser armazenado apenas no armazenamento protegido do sistema (Keychain / Keystore). Se o aplicativo receber um sinal de foreground do sistema, o refresh token é verificado e, se necessário, renovado antes que o usuário comece a interagir.
Refresh token rotation é um mecanismo onde cada solicitação para renovar um access token retorna um novo refresh token, e o antigo é revogado. Se um invasor roubou o refresh token e o usa, o cliente legítimo receberá um erro na próxima tentativa de renovação — o servidor detecta que o refresh token já foi usado (reuse detection). A rotação é uma recomendação obrigatória da OAuth 2.0 Security Best Current Practice (RFC 9700) para todos os sistemas que trabalham com tokens de longa duração em ambiente móvel.
O algoritmo de detecção funciona da seguinte forma: o servidor armazena uma marcação "usado" no banco de dados para cada refresh token emitido. Ao receber uma solicitação de renovação, o servidor verifica — se o refresh token já está marcado como usado, ocorreu uma tentativa de reutilização. O servidor invalida imediatamente todos os refresh tokens dessa sessão e bloqueia o acesso. O usuário legítimo é redirecionado para a página de login. Isso previne ataques de roubo de refresh token: o invasor obtém acesso, mas a sessão é bloqueada assim que detectada.
De acordo com OAuth Security Workshop, 2025, implementar rotation + reuse detection reduz a probabilidade de um ataque bem-sucedido via refresh token roubado de 23% para 0,3%. Para implementar a detecção de reutilização, o servidor armazena o hash do último refresh token emitido emparelhado com o client_id. Em uma solicitação de renovação, o servidor compara o refresh token apresentado com o armazenado — se não coincidirem, ocorreu reutilização e toda a cadeia de tokens é revogada.
Ao receber um erro invalid_grant, o cliente deve realizar um logout completo: limpar todos os tokens armazenados (access e refresh), encerrar a sessão atual no dispositivo e redirecionar o usuário para a tela de login. A reautenticação cria uma nova cadeia de tokens não relacionada à anterior. Ignorar este erro e tentar renovar novamente levará a um bloqueio por detecção de reutilização.
Um exemplo de implementação da renovação de token do lado do cliente em Kotlin para Android. O aplicativo intercepta a resposta HTTP 401, aciona uma solicitação de renovação e tenta novamente a solicitação original com o novo access token. O OkHttp Interceptor é usado — um componente chave para gerenciamento automático de tokens sem duplicar lógica em cada solicitação.
class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val accessToken = getAccessToken()
val authRequest = request.newBuilder()
.addHeader("Authorization", "Bearer $accessToken")
.build()
val response = chain.proceed(authRequest)
if (response.code != 401) return response
// Access token expirou — renovando via refresh token
val newToken = refreshAccessToken() ?: return response
return chain.proceed(request.newBuilder()
.addHeader("Authorization", "Bearer $newToken")
.build())
}
private fun refreshAccessToken(): String? {
val refreshToken = getRefreshToken() ?: return null
val client = OkHttpClient()
val body = FormBody.Builder()
.add("grant_type", "refresh_token")
.add("refresh_token", refreshToken)
.build()
val request = Request.Builder()
.url("https://auth.example.com/oauth/token")
.post(body)
.build()
val response = client.newCall(request).execute()
val json = JSONObject(response.body?.string() ?: return null)
val newAccessToken = json.getString("access_token")
// Salvar novo refresh token durante rotation
saveTokens(newAccessToken, json.optString("refresh_token"))
return newAccessToken
}
}
Perguntas frequentes
Access token é um token de curta duração para acesso à API, enviado com cada requisição. Um refresh token é um token de longa duração para obter um novo access token, enviado apenas ao endpoint de token. O refresh token não deve estar acessível aos endpoints normais da API do aplicativo.
A cada expiração — normalmente a cada 15–60 minutos. O cliente deve rastrear o tempo de expiração (verificando exp no JWT ou usando um timer) e iniciar a solicitação de renovação antecipadamente, antes de receber efetivamente um 401. Isso evita perda de dados em requisições enviadas no momento da expiração do token.
Sim, um refresh token pode e deve ser revogado. O servidor mantém uma lista de refresh tokens ativos (ou seus hashes) no banco de dados. Ao fazer logout, alterar a senha ou em caso de atividade suspeita, o servidor remove a entrada do banco de dados, e a próxima solicitação de renovação com esse token retornará um erro invalid_grant.
Com rotation e detecção de reutilização ativados: a primeira solicitação renova os tokens com sucesso, a segunda recebe um erro invalid_grant. O servidor também registra a reutilização — a sessão é bloqueada, ambos os clientes perdem o acesso. O usuário deve fazer login novamente. Isso sacrifica a conveniência pela segurança.
Um refresh token deve ser armazenado no Keychain com o atributo kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Isso garante a criptografia do token, inacessibilidade quando o código de acesso for removido e evita a sincronização via iCloud. Usar UserDefaults ou CoreData para armazenar o token é estritamente proibido.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também