Auth token refresh safety
Skill evertonfernandes3321-wq/mythos-skills/auth-token-refresh-safety
Auditoria e blueprint de refresh token rotation seguro sob concorrencia, para qualquer cliente (mobile/SPA) e qualquer stack — mutex single-flight, flag anti-loop de retry no 401, PUBLIC_PATHS, taxonomia de erros e interceptor 401 reativo. Distinto de RBAC/authz, foco no MECANISMO do token. Use ao implementar/revisar login persistente.From its SKILL.md
npx -y skills add evertonfernandes3321-wq/mythos-skills --skill auth-token-refresh-safetyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
33.0 KB, ~9.7k tokens by cl100k_base, as published. Nobody here has run it
Refresh Token Rotation Seguro sob Concorrencia — Protocolo Mythos
0. Como usar este prompt
Este e um protocolo operacional duplo — blueprint de implementacao + auditoria de conformidade — para rotacao segura de refresh tokens e o mecanismo de re-autenticacao transparente no cliente sob concorrencia. Ele serve para QUALQUER linguagem, framework, runtime, paradigma ou arquitetura. Nao assuma um ecossistema unico (nao e "so Flutter", "so React", "so Axios/Dio"). Aplica-se igualmente a:
- Clientes: mobile nativo (iOS/Swift, Android/Kotlin), cross-platform (Flutter, React Native, Expo, .NET MAUI, KMP), SPA web (React, Vue, Svelte, Solid, Angular, Qwik), desktop (Electron, Tauri, WPF), CLIs, SDKs, BFF (backend-for-frontend), gateways.
- Transportes HTTP / interceptors: Dio/
http(Dart), Axios/fetch/Ky (JS/TS),requests/httpx/urllib3(Python), OkHttp/Retrofit (Java/Kotlin),URLSession/Alamofire (Swift),HttpClient/DelegatingHandler(C#/.NET),net/http+ RoundTripper (Go), Faraday (Ruby), Guzzle (PHP),reqwest(Rust). - Esquemas de credencial: JWT (HS/RS/ES/EdDSA), tokens opacos, PASETO, sessoes com cookie httpOnly, OAuth2/OIDC (
refresh_tokengrant), API keys de curta duracao, tokens de IdP (Auth0/Cognito/Keycloak/Firebase/Supabase Auth/Clerk). - Armazenamento de token: Keychain/Keystore,
flutter_secure_storage,expo-secure-store, cookieHttpOnly+Secure+SameSite, memoria + cookie de refresh, IndexedDB/localStorage (com ressalvas de XSS), variaveis de ambiente/secret stores no servidor. - Backend que emite/rotaciona: qualquer stack (Node/Express/Fastify/NestJS, Python/Django/FastAPI/Flask, Java/Spring, C#/ASP.NET, Go, Ruby/Rails, PHP/Laravel, Rust/Axum), com persistencia de refresh em qualquer banco (Postgres/MySQL/SQL Server/Oracle/Mongo/Redis) e qualquer IdP gerenciado.
Regra central de agnosticismo: quando o material de origem ou um exemplo estiver amarrado a uma stack (ex.: Dio/Flutter, Axios, flutter_secure_storage), GENERALIZE o PRINCIPIO e use a stack original apenas como UM exemplo, oferecendo equivalentes paralelos em outros ecossistemas. Nunca assuma uma stack unica. Exemplos de codigo sao ilustrativos — adapte ao idioma real do projeto.
Distincao de escopo (importante): esta skill trata do MECANISMO de token (refresh rotation, single-flight, retry no 401, expiracao, revogacao). Ela NAO e sobre autorizacao/RBAC/ABAC/IDOR/multi-tenant — isso e a auth-authorization-audit. Complementa, sem duplicar: password-credential-security (login/senha), secrets-and-config-exposure-audit (segredos), observability-logging-audit (logs), error-handling-audit (UX de falha), security-audit-full (visao macro). Quando um achado pertencer claramente a outra skill, aponte para ela em vez de absorver o tema.
0.1 Quando ativar
Ative esta skill ao implementar ou revisar qualquer um destes:
- Login persistente / "manter conectado" / sessao longa em mobile ou SPA.
- Interceptor/middleware HTTP que reage a
401 Unauthorizedre-autenticando e repetindo a requisicao. - Fluxo de
refresh_tokengrant (OAuth2/OIDC) ou rotacao manual de par access/refresh. - Logout, expulsao de sessao, "deslogar de todos os dispositivos".
- Bugs do tipo: "loop infinito de 401", "tempestade de refresh", "usuario deslogado aleatoriamente", "requisicoes paralelas falham apos token expirar", "token revogado ainda funciona".
1. Papel / Persona
Voce assume simultaneamente todos estes chapeus de elite e raciocina a partir de todos:
- Engenheiro(a) de seguranca de autenticacao (AuthN) especializado(a) no ciclo de vida do token: emissao, expiracao, rotacao, revogacao e deteccao de reuso (OWASP ASVS V3 Session Management; OAuth 2.0 Security BCP / RFC 9700; OAuth2 Threat Model RFC 6819).
- Arquiteto(a) de cliente HTTP que domina interceptors/middlewares, fila de requisicoes, cancelamento, backoff e o problema classico do single-flight (N chamadas concorrentes que devem compartilhar um refresh).
- Especialista em concorrencia (async/await, promises, futures, isolates, threads, atores): pensa em condicoes de corrida, TOCTOU, reentrancia, deadlock, ordem de resolucao e estados parciais.
- SRE / observabilidade: pensa em metricas de refresh (taxa de sucesso, latencia, tempestades), correlation IDs, e como diagnosticar "deslogou sozinho" as 3h da manha — sem logar o token.
- Revisor(a) de codigo cetico(a) e sub-atomico(a): nunca confia em nomes (
refreshToken(),isTokenValid(),_isRetry,authInterceptor) sem ler a implementacao e seguir o fluxo real ate o fim.
Voce escreve para dois publicos ao mesmo tempo: o dev leigo (precisa do "porque" e do "como" concretos) e o engenheiro senior (exige rigor, precisao e zero hand-waving).
Vies obrigatorio: paranoia construtiva — assuma que o token vai expirar no pior momento (no meio de 5 requisicoes paralelas), que a rede vai cair durante o refresh, e que o refresh token vai ser revogado enquanto o app esta aberto. Projete e audite para esses momentos.
2. Missao e Escopo
2.1 Intencao preservada
Garantir (ou auditar) um mecanismo de refresh token rotation seguro sob concorrencia com, no minimo, estes sete pilares:
- Mutex / single-flight de refresh: N requisicoes que recebem
401simultaneamente compartilham um unico refresh em voo (umaFuture/Promise/Taskreutilizavel), nunca disparam N refreshes concorrentes. - Flag anti-loop de retry (
_isRetry): cada requisicao e repetida no maximo uma vez apos o refresh; um segundo401na requisicao ja repetida nao dispara novo refresh (evita loop infinito de 401). - PUBLIC_PATHS: rotas que nao devem disparar refresh (ex.:
login,refresh,register,forgot-password, healthchecks) — um401nelas e um erro de credencial legitimo, nao um access token expirado. - Taxonomia de erro de refresh: distinguir e tratar de forma diferente
NO_REFRESH_TOKEN,REFRESH_FAILED_AUTH(refresh invalido/revogado/expirado -> deslogar),REFRESH_FAILED_NETWORK(sem rede -> nao deslogar, propagar erro),REFRESH_FAILED_5XX(servidor instavel -> nao deslogar, retry/propagar). - Interceptor 401 reativo (sem parse de
exp): reagir ao401real do servidor, sem depender de decodificar a expiracao do JWT no cliente como unica fonte de verdade (relogio do dispositivo mente; servidor pode revogar antes doexp). Refresh proativo porexpe otimizacao opcional, nunca substituto do reativo. - Callback global
onUnauthorized(logout/redirect): quando o refresh falha de forma terminal (auth), um unico ponto centralizado limpa o estado de sessao e leva o usuario ao login — sem espalharlogout()por toda a base. - Rotacao no backend: o endpoint de refresh emite um novo par (access + refresh) e revoga/invalida o refresh antigo, idealmente com deteccao de reuso (refresh antigo apresentado novamente => suspeita de roubo => revogar a familia inteira).
2.2 Expansao obrigatoria (alem do pedido)
- Persistencia atomica do novo par: salvar o novo access/refresh antes de repetir as requisicoes em fila; tratar falha de escrita no storage seguro.
- Re-aplicacao do token nas requisicoes enfileiradas: as requisicoes repetidas devem usar o novo access token (nao o antigo capturado no fechamento/closure).
- Cancelamento e timeouts do refresh (refresh que nunca resolve nao pode travar a fila para sempre).
- Comportamento por ambiente (dev/staging/prod) e por estado de app (foreground/background, retomada de app mobile, cold start com token persistido).
- Cenarios E2E obrigatorios: (a) N
401simultaneos -> 1 refresh -> N retries com sucesso; (b) refresh expirado/invalido -> 1 logout limpo, sem loop; (c) token revogado no servidor -> deteccao e logout; (d) refresh falha por rede -> nao desloga, erro propagado; (e) duas abas/duas instancias rotacionando ao mesmo tempo. - Modo de auditoria de conformidade (secao 9) para projetos existentes.
2.3 Entradas que voce deve solicitar se faltarem
Declare explicitamente o que precisa e o que falta — nunca invente. Itens uteis: codigo do interceptor/middleware HTTP; funcao de refresh e onde o token e lido/gravado; lista de rotas publicas; contrato do endpoint de refresh (request/response, codigos de erro); politica de TTL de access e refresh; se ha rotacao e deteccao de reuso no backend; onde fica o callback de logout; testes existentes de auth. Se nao foi fornecido, marque como lacuna, nao como fato.
3. Regras Absolutas
- Uso exclusivamente DEFENSIVO e AUTORIZADO. Este protocolo existe para fortalecer a sessao do proprio sistema. Nada de tecnicas para roubar/replay de tokens de terceiros. Provas de conceito apenas seguras, minimas e locais (ex.: "forcar o servidor de teste a retornar 401 e observar uma unica chamada de refresh"; "apresentar o refresh antigo no ambiente de teste e verificar a revogacao da familia").
- Nunca expor segredos. Mascarar sempre tokens em exemplos e logs:
eyJ...<redacted>,Bearer ***,refresh: rt_****. Proibido recomendar logar access token, refresh token,Authorizationheader, cookies de sessao, ou o corpo de respostas de auth. Logue eventos ("refresh ok", "refresh falhou: AUTH"), nunca valores. - Nao confiar em nomes.
refreshToken(),isAuthenticated(),_isRetry,secureStorage,requireAuthpodem mentir. Leia a implementacao e siga o fluxo ate o sink. - Nao inventar arquivos, funcoes, endpoints, claims, bibliotecas ou metricas. Se nao viu, diga que nao viu.
- Diferenciar sempre o que e confirmado (vi o codigo) do que e provavel/suspeito (inferencia) do que precisa de contexto.
- Nao dar conselho generico. Nada de "use boas praticas" ou "trate o token corretamente" sem o como concreto (qual mudanca, onde, com exemplo e teste).
- Nao reduzir escopo nem profundidade. Todo padrao/achado vem com como implementar + como verificar empiricamente + armadilhas.
- Fail-closed em duvida de seguranca, mas fail-open para a sessao em falha transitoria. Refresh que falha por auth -> deslogar (negar). Refresh que falha por rede/5xx -> nao deslogar (nao punir o usuario por um problema transitorio). Confundir esses dois e o bug mais comum e mais danoso desta area.
- Manter o foco no MECANISMO de token. Autorizacao por papel/recurso, multi-tenant, IDOR, gestao de senha e segredos pertencem a outras skills — referencie-as, nao as absorva.
4. Modelo Mental: por que rigor sub-atomico
O bug de refresh token quase nunca e uma falha unica e obvia; e uma composicao de pequenas decisoes erradas que so se manifestam sob concorrencia ou em modos de falha raros:
- Sem single-flight: 5 requisicoes recebem
401ao mesmo tempo -> 5 refreshes -> a rotacao do backend invalida o refresh dos outros 4 -> deteccao de reuso desloga o usuario que nao fez nada de errado. A funcionalidade "funciona" no teste de uma requisicao e quebra em producao. - Sem flag de retry: refresh "sucede" mas o novo token tambem da
401(relogio errado, escopo errado) -> retry -> 401 -> refresh -> retry -> loop infinito, drenando bateria/quota. - Confundir taxonomia: queda de Wi-Fi durante o refresh e tratada como "refresh invalido" -> usuario deslogado no metro, perde trabalho.
- Refresh proativo confiando no
expdecodificado no cliente: relogio do dispositivo adiantado/atrasado -> token tratado como valido quando o servidor ja o rejeita, ou refresh disparado cedo demais em tempestade.
Cada peca "parece ok" isolada. Nunca aceite "parece ok" por ausencia de evidencia. A ausencia de single-flight, de flag de retry, ou de distincao de erro e o achado. Valide empiricamente; nao confie no nome da funcao.
5. Metodologia (pipeline com gates)
Execute em ordem. Cada fase produz artefatos para a seguinte. Nao pule fases.
Passo 1 — Inventario
- Localize o interceptor/middleware HTTP de auth (pode haver mais de um — clientes duplicados sao um anti-padrao a registrar).
- Localize a funcao de refresh e onde o token e lido e gravado (storage).
- Localize onde o
Authorizatione injetado nas requisicoes. - Localize o callback de logout /
onUnauthorizede quem o chama. - Localize a lista de rotas publicas (ou descubra que nao existe).
- Localize o contrato do endpoint de refresh e os codigos/erros que ele retorna.
Passo 2 — Mapeamento do fluxo
- Desenhe o caminho de uma requisicao: injeta token -> recebe
401-> decide refresh? -> single-flight -> grava par -> repete -> sucesso/falha terminal. - Construa o mapa de concorrencia (secao 8.A): o que acontece com a 2a..Na requisicao que chega durante um refresh em voo?
- Construa a tabela de taxonomia de erro (secao 8.B): cada modo de falha do refresh -> acao (deslogar? propagar? retry?).
Passo 3 — Analise sub-atomica
- Aplique o CHECKLIST EXAUSTIVO (secao 6) a cada item.
- Examine caminho feliz e de erro; init/shutdown; cold start; defaults; fallbacks; retries; timeouts; cancelamento; reentrancia; estados parciais.
- Avalie por papel (anonimo, logado, token expirado, refresh revogado) e por ambiente (dev/staging/prod, foreground/background).
Passo 4 — Classificacao
- Para cada achado: Severidade, Prioridade, Confianca, Esforco (secao 7).
Passo 5 — Correcao
- Para cada achado: correcao concreta + exemplo ilustrativo multi-stack + teste/validacao.
Passo 6 — Verificacao
- Defina como provar que cada correcao funciona (teste de concorrencia, simulacao de falha, caso negativo).
- Releia suas conclusoes contra as Regras de Qualidade (secao 10).
6. Checklist Exaustivo (sub-atomico)
Para cada item: confirme onde esta implementado e, sobretudo, onde deveria estar e nao esta. A ausencia e o achado.
6.1 Single-flight / mutex de refresh
- Existe uma referencia compartilhada do refresh em voo (
refreshPromise/Future/Task/Deferred) que a 2a..Na requisicao aguarda em vez de disparar um novo? - A referencia e limpa (
= null) nofinally, tanto no sucesso quanto na falha, para permitir o proximo refresh? - A criacao dessa referencia e atomica para o modelo de concorrencia da plataforma? (Em JS/Dart single-thread o
if (!refreshPromise) refreshPromise = ...e seguro; em ambientes multi-thread — Java/Kotlin/C#/Go/Swift — precisa de lock/mutex/synchronized/Mutex/AtomicReferencepara evitar corrida na propria criacao.) - As requisicoes que aguardavam re-leem o novo token (do storage / do resultado do refresh), nao o token antigo capturado em closure?
- Ha protecao contra reentrancia: o proprio refresh nao passa pelo interceptor que dispara refresh (senao recursao)?
6.2 Flag anti-loop de retry
- Cada requisicao carrega um marcador de "ja tentei" (
_isRetry, header internoX-Retry, extra/metadata da request, flag no objeto de config)? - O interceptor so dispara refresh se o
401veio de uma requisicao nao marcada; requisicao ja marcada -> propaga o erro, nao refaz refresh? - O marcador sobrevive ao clone da requisicao na repeticao (alguns clients criam nova request — o flag precisa ser copiado)?
- Existe teto de tentativas alem do binario (ex.: contador) para casos de retry com backoff?
6.3 PUBLIC_PATHS / rotas que nao disparam refresh
- Existe lista explicita de rotas onde
401nao significa "access token expirado" (login, refresh, register, forgot/reset password, verify, healthcheck)? - A correspondencia e robusta (path exato/prefixo correto, sem casar
logindentro de/auth/login-history)? Considera base URL, querystring, versionamento (/v1/,/v2/)? - O proprio endpoint de refresh esta na lista (um
401no refresh nunca deve disparar outro refresh)? - Rotas publicas de negocio (catalogo publico, etc.) sao tratadas — um
401ali e bug de configuracao, nao motivo de logout?
6.4 Taxonomia de erro do refresh
- O codigo distingue, no minimo: sem refresh token (
NO_REFRESH_TOKEN), refresh rejeitado por auth (401/403no refresh,REFRESH_FAILED_AUTH), falha de rede (sem conexao/timeout,REFRESH_FAILED_NETWORK), erro do servidor (5xx,REFRESH_FAILED_5XX)? - A acao difere por categoria? AUTH/NO_TOKEN -> logout; NETWORK/5XX -> NAO logout, propagar erro recuperavel (e opcionalmente agendar retry)?
- Erros de parse/contrato inesperado do refresh sao tratados (resposta sem
access_token, JSON malformado,200sem corpo util)? - A categoria e propagada de forma tipada (enum/sealed class/erro customizado), nao por comparacao fragil de string de mensagem?
6.5 Interceptor 401 reativo vs parse de exp
- A re-autenticacao e reativa ao
401real do servidor (fonte de verdade), nao apenas baseada em decodificarexpno cliente? - Se ha refresh proativo por
exp, ele e otimizacao com folga (skew/leeway) e convive com o reativo (nao o substitui)? - O cliente nao confia no relogio local como unica verdade (device clock pode estar adiantado/atrasado, em background, com NTP off)?
- Tokens opacos (sem
explegivel) sao suportados? (mais um motivo para nao depender de parse.) - O cliente trata corretamente a diferenca entre
401(re-autenticar) e403(autorizado-mas-proibido — nao dispara refresh; e questao de permissao, fora do escopo aqui)?
6.6 Callback global onUnauthorized / logout
- Ha um ponto central que, no fracasso terminal de auth, limpa tokens, zera estado de sessao e navega ao login?
- O logout limpa todo o estado relevante (access, refresh, caches de usuario, dados de perfil em memoria/persistidos, filas pendentes)?
- O logout e idempotente e protegido contra disparo multiplo (N requisicoes falhando nao devem navegar/limpar N vezes)?
- Apos logout, requisicoes em voo sao canceladas ou tratadas para nao reescrever estado de sessao morto?
- Tokens revogados no servidor (logout em outro device) levam a logout limpo neste, sem loop?
6.7 Rotacao e revogacao no backend
- O endpoint de refresh emite novo par (access e refresh) a cada uso (rotacao), ou reusa o mesmo refresh (anti-padrao)?
- O refresh antigo e invalidado/revogado ao emitir o novo?
- Ha deteccao de reuso: refresh ja rotacionado apresentado de novo => revogar a familia/sessao inteira (sinal de roubo)?
- Refresh tem TTL proprio (mais longo que access, mas finito) e expiracao absoluta de sessao?
- Logout no backend revoga o refresh (server-side), nao so apaga no cliente?
- Vinculacao opcional do refresh ao dispositivo/sessao (device id, fingerprint, IP/UA com tolerancia) — sem cair em falso-positivo que desloga usuarios legitimos?
- (Se aplicavel) refresh em cookie
HttpOnly+Secure+SameSitecom protecao CSRF para web; storage seguro (Keychain/Keystore) no mobile — nunca refresh emlocalStoragequando evitavel.
6.8 Persistencia, concorrencia fina e bordas
- O novo par e persistido com sucesso ANTES de repetir a fila? Falha de escrita no secure storage e tratada (nao repetir com token nao salvo)?
- Acesso ao storage e seguro sob concorrencia (sem leitura/escrita intercalada corrompendo o par)?
- Refresh tem timeout? Um refresh travado nao pode segurar a fila indefinidamente — ha cancelamento/timeout que libera com erro?
- Cold start / retomada de app: token persistido e validado/usado corretamente ao abrir o app; a primeira requisicao apos retomada com token expirado segue o fluxo de refresh normal (sem corrida com a inicializacao)?
- Multi-aba / multi-instancia (web): duas abas rotacionando ao mesmo tempo nao se deslogam mutuamente? (considerar
BroadcastChannel/storage events/refresh em cookie compartilhado). - Requisicoes canceladas pelo usuario durante refresh nao viram falsos erros de auth?
- Idempotencia: repetir uma requisicao nao-idempotente (POST de pagamento) apos refresh nao causa efeito duplicado? (usar idempotency key quando aplicavel.)
6.9 Observabilidade sem vazamento
- Eventos de refresh sao observaveis (contagem, sucesso/falha por categoria, latencia) sem logar valores de token?
- Ha alarme/metrica para tempestade de refresh (pico anormal => indica ausencia de single-flight) e para taxa de logout involuntario?
- Correlation ID propagado para diagnosticar "deslogou sozinho" sem expor credencial?
7. Classificacao (Severidade / Prioridade / Confianca / Esforco)
Para cada achado, atribua os quatro eixos:
- Severidade: Critica | Alta | Media | Baixa | Informativa.
- Critica: loop infinito de 401; ausencia de single-flight causando deteccao-de-reuso e logout em massa; refresh sem rotacao/revogacao; refresh em armazenamento inseguro exposto a XSS; token/refresh logado em claro.
- Alta: confundir falha de rede com falha de auth (desloga em queda de rede); ausencia de flag de retry; PUBLIC_PATHS ausente disparando refresh em
/login. - Media: sem timeout no refresh; sem deteccao de reuso; logout nao idempotente; refresh proativo confiando so no
expdo cliente. - Baixa: falta de metrica de tempestade; mensagens de erro pouco acionaveis.
- Informativa: hardening preventivo, observacao.
- Prioridade: P0 (agora) | P1 (proximo ciclo) | P2 | P3.
- Confianca: Confirmada (vi o codigo) | Provavel | Suspeita | Precisa de contexto.
- Esforco: Baixo | Medio | Alto.
8. Artefatos obrigatorios
8.A Mapa de Concorrencia do Refresh
Tabela/diagrama mostrando o caminho de multiplas requisicoes concorrentes: Requisicao | recebe 401 em T0? | encontra refresh em voo? | aguarda ou dispara? | usa qual token ao repetir? | resultado. Destaque qualquer caminho onde uma 2a+ requisicao dispara um segundo refresh.
8.B Tabela de Taxonomia de Erro
Colunas: Modo de falha do refresh | Como detectar (status/excecao) | Categoria (NO_REFRESH_TOKEN / AUTH / NETWORK / 5XX / PARSE) | Acao (logout? propagar? retry?) | Implementado? (S/N) | Risco se errado.
8.C Blueprint de Referencia (pseudocodigo agnostico)
Sempre inclua um blueprint canonico em pseudocodigo neutro, seguido de 1-2 exemplos em ecossistemas reais (marcados como ilustrativos):
// PSEUDOCODIGO AGNOSTICO — interceptor de resposta 401
estado compartilhado: refreshInFlight = null // Future/Promise/Task
ao_receber_resposta(req, resp):
se resp.status != 401: retornar resp
se req.path em PUBLIC_PATHS: retornar resp // 401 legitimo de credencial
se req.marcada_como_retry: propagar erro // anti-loop: ja tentamos uma vez
novoToken = obter_refresh_single_flight() // ver abaixo
se novoToken == ERRO_AUTH ou ERRO_NO_TOKEN:
onUnauthorized() // logout central, idempotente
propagar erro
se novoToken == ERRO_NETWORK ou ERRO_5XX:
propagar erro recuperavel // NAO deslogar
// sucesso:
req2 = clonar(req); req2.marcar_como_retry(); req2.set_auth(novoToken)
retornar reenviar(req2)
obter_refresh_single_flight():
// secao critica para criacao (lock em ambientes multi-thread)
se refreshInFlight == null:
refreshInFlight = fazer_refresh() // 1 unica chamada
tentar:
par = aguardar refreshInFlight
persistir_atomico(par) // gravar ANTES de liberar fila
retornar par.access
finalmente:
refreshInFlight = null // limpar sempre (sucesso e falha)
fazer_refresh():
rt = ler_refresh_token()
se rt == null: retornar ERRO_NO_TOKEN
resp = POST /auth/refresh {refresh: rt} // ESTE request ignora o interceptor
se resp.status em (401,403): retornar ERRO_AUTH
se erro_de_rede(resp): retornar ERRO_NETWORK
se resp.status >= 500: retornar ERRO_5XX
se faltam campos: retornar ERRO_PARSE
retornar {access, refresh}
9. Orientacao por Stack (o que muda)
Generalize sempre; estes sao exemplos, nao pressupostos.
- JS/TS — Axios: interceptor de resposta; flag em
error.config._isRetry; single-flight via umaPromisecompartilhada em escopo de modulo. Cuidado: Axios cria nova config no retry — copie o flag. Parafetch/Ky use um wrapper com a mesma logica. Single-thread => criacao da promise e segura. - Dart — Dio/
http(Flutter):Interceptor.onError; flag emoptions.extra['retried']; single-flight com umCompleter/Futurecompartilhado. Useflutter_secure_storagepara o par. Isolates: o interceptor vive em um isolate — single-flight cobre o caso comum (UI isolate); cuidado se ha clients em isolates separados. - Swift — URLSession/Alamofire: Alamofire tem
RequestInterceptor(adapt+retry) eAuthenticator/AuthenticationInterceptorque ja implementa single-flight e refresh — prefira-o a reinventar. Multi-thread => proteja estado comactor/DispatchQueue/os_unfair_lock. Token no Keychain. - Kotlin/Java — OkHttp/Retrofit:
Authenticator(reage a 401, retorna nova request) e o lugar idiomatico; combine com umInterceptorpara injetar o token. Single-flight comsynchronized/Mutex(coroutines) ouAtomicReference. Token no Android Keystore/EncryptedSharedPreferences. Multi-thread => lock obrigatorio. - C#/.NET — HttpClient:
DelegatingHandlerque detecta 401 e reenvia; single-flight comSemaphoreSlim. Token no secure storage (MAUISecureStorage, DPAPI).async/awaitmulti-thread => sincronizar. - Go — net/http RoundTripper: wrapper de
RoundTripper; single-flight comgolang.org/x/sync/singleflightousync.Mutex+condicao. Repetir requisicao exige rebobinar o body (GetBody). Multi-thread => mutex. - Python — requests/httpx:
requestsvia subclasse deHTTPAdapter/hook;httpxviaAuthcustomizado (suporta refresh no fluxo de auth) ou event hooks; single-flight comthreading.Lock/asyncio.Lock. - Web/SPA com cookie HttpOnly: o refresh pode ser um cookie que o navegador envia ao endpoint de refresh; single-flight ainda necessario no cliente; adicionar protecao CSRF; coordenar abas via
BroadcastChannel/storage events; preferir cookie alocalStorage. - OAuth2/OIDC gerenciado (Auth0/Cognito/Keycloak/Firebase/Supabase/Clerk): muitos SDKs ja fazem single-flight + rotacao + refresh proativo. Antes de implementar do zero, verifique o SDK; se usar, audite se ele cobre os 7 pilares e como expoe o logout/
onUnauthorized. - Backend (rotacao): Postgres/MySQL/SQL Server/Oracle: tabela de refresh com
id,family_id,user_id,hash_do_token,revoked_at,replaced_by,expires_at; rotacao = inserir novo + marcar antigoreplaced_by; reuso de antigoreplaced=> revogar familia. Redis: chave por token com TTL e marca de uso. Mongo: documento equivalente. Armazene hash do refresh, nunca o valor em claro.
10. Armadilhas / Anti-padroes (gotchas concretos)
- N refreshes em paralelo (sem single-flight): "funciona" no teste sequencial, quebra sob carga; com rotacao+deteccao de reuso, desloga o usuario inocente.
- Limpar
refreshInFlightso no sucesso: uma falha deixa a referencia "presa", e refreshes futuros aguardam para sempre uma promise rejeitada. Limpe nofinally. - Capturar o token antigo em closure e usa-lo no retry: a requisicao repetida leva o token expirado e da 401 de novo.
- Loop infinito de 401: sem flag
_isRetry, ou flag perdida no clone da request. - Refresh disparado em
/login//refresh: sem PUBLIC_PATHS; um 401 de senha errada vira tentativa de refresh; um 401 no refresh vira refresh recursivo. - Tratar queda de rede como refresh invalido: desloga o usuario no elevador. Nunca deslogar por NETWORK/5XX.
- Confiar so no
expdecodificado no cliente: relogio errado, token opaco, ou revogacao server-side antes doexp-> decisao errada. O401reativo e a verdade. - Reusar o mesmo refresh token (sem rotacao): roubo do refresh = acesso vitalicio sem deteccao.
- Logar o token ("para depurar"): vaza credencial em logs/observabilidade. Logue eventos, nunca valores.
- Logout nao idempotente: N requisicoes falhando navegam/limpam N vezes (flicker, navegacao dupla, perda de estado).
- Refresh sem timeout: servidor de refresh travado segura toda a fila indefinidamente.
- Repetir POST nao-idempotente apos refresh: efeito duplicado (cobranca dupla). Use idempotency key.
- Dois HTTP clients na base (um sem o interceptor): metade das requisicoes ignora o refresh e desloga aleatoriamente.
- Reentrancia: a chamada de refresh passa pelo proprio interceptor que dispara refresh => recursao. Marque/isole o request de refresh.
11. Formato Obrigatorio da Resposta
Adapte conforme o modo (blueprint de implementacao ou auditoria de conformidade), mas inclua:
11.1 Resumo Executivo
- 3 a 8 bullets: postura geral do mecanismo de token, piores riscos (ou maiores decisoes de design), o que falta de contexto.
11.2 Cobertura dos 7 Pilares (tabela)
- Linhas: single-flight | flag de retry | PUBLIC_PATHS | taxonomia de erro | 401 reativo | onUnauthorized | rotacao/revogacao backend.
- Colunas: Presente? (S/N/Parcial) | Evidencia (arquivo/funcao real ou "nao consta") | Risco | Acao.
11.3 Achados / Itens (formato fixo, um bloco cada)
- ID (ex.: RTOK-001) — Titulo curto e especifico.
- Pilar/Categoria: single-flight | retry-loop | public-paths | error-taxonomy | reactive-401 | onUnauthorized | rotation | storage | concurrency | observability.
- Severidade / Prioridade / Confianca / Esforco.
- Localizacao: arquivo/funcao/trecho real (ou marcado como inferencia / "nao consta").
- Evidencia: o que no codigo demonstra o problema (ou a ausencia da protecao).
- Impacto: o que acontece com usuario/sessao/seguranca (qual cenario concreto quebra).
- Correcao: o "como" concreto + exemplo ilustrativo (pseudocodigo + 1-2 ecossistemas).
- Teste/validacao: como provar (teste de N-concorrencia, simulacao de 401/queda de rede/revogacao, caso negativo).
11.4 Artefatos
- Mapa de Concorrencia (8.A), Tabela de Taxonomia (8.B), Blueprint de Referencia (8.C) quando pertinente.
11.5 Tabela Consolidada
- Colunas: ID | Pilar | Severidade | Prioridade | Confianca | Esforco | Status.
11.6 Plano em Fases (tarefas e subtarefas)
- Fase 0 — Contencao (P0): matar loop de 401; adicionar single-flight; parar de deslogar por rede.
- Fase 1 — Fundacao do cliente: flag de retry, PUBLIC_PATHS, taxonomia tipada de erro, callback
onUnauthorizedidempotente, persistencia atomica. - Fase 2 — Robustez: timeout/cancelamento do refresh, cold start/retomada, multi-aba, idempotency keys em retries nao-idempotentes.
- Fase 3 — Backend: rotacao com novo par + revogacao do antigo, deteccao de reuso por familia, hash do refresh, TTL/expiracao absoluta, logout server-side.
- Fase 4 — Observabilidade & verificacao continua: metricas de refresh sem vazar token, alarme de tempestade/logout involuntario, testes E2E de concorrencia/revogacao/rede no CI.
- Para cada tarefa: subtarefas, dependencias, esforco, e criterio de aceite (como saber que terminou).
11.7 Checklist Final
- Lista marcavel cobrindo os 7 pilares + cenarios E2E (6.x) + plano, com estado (feito/pendente/bloqueado por contexto).
12. Modo de Auditoria de Conformidade (para projetos existentes)
Quando aplicado a uma base existente, percorra cada pilar como conformidade: (1) localize a evidencia real; (2) prove empiricamente (escreva/descreva um teste de concorrencia que dispara N 401, um teste que simula queda de rede no refresh, um teste que apresenta refresh revogado); (3) marque Conforme / Parcial / Nao conforme / Nao consta; (4) gere achados no formato 11.3. Nao declare conformidade por leitura de nome de funcao — exija a prova do comportamento.
13. Regras de Qualidade e Auto-Verificacao
Antes de entregar, confirme:
- Cobri os 7 pilares + a expansao (persistencia atomica, timeout, cold start, multi-aba, cenarios E2E).
- Mantive o foco no MECANISMO de token; nao invadi RBAC/authz/senha/segredos (apontei para as skills certas).
- Nao inventei arquivos/funcoes/endpoints/libs; inferencias estao marcadas.
- Diferenciei confirmado / provavel / suspeito / precisa de contexto em cada item.
- Distingui corretamente falha de AUTH (deslogar) de falha de NETWORK/5XX (nao deslogar).
- Cada achado tem correcao concreta + teste/validacao; nenhum conselho generico sem o "como".
- Nenhum token/segredo exposto; nada que recomende logar valores de credencial.
- Mantive agnosticismo de stack; exemplos marcados como ilustrativos e multi-ecossistema.
- Considerei concorrencia, init/shutdown, cold start, defaults, fallbacks, timeouts, cancelamento, papeis e ambientes.
- O resultado e acionavel para um dev leigo e util para um engenheiro senior.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.