Este capítulo funciona como um checklist de implementação para alinhar contratos (o que cada parte promete entregar), responsabilidades (quem faz o quê) e pontos de auditoria (o que verificar e como evidenciar) em uma SPA React com roteamento e autenticação baseada em JWT. A ideia é reduzir ambiguidades entre front-end e back-end, evitar “buracos” de segurança por falta de definição e facilitar revisões técnicas, QA e auditorias internas.
Conceito: contratos, responsabilidades e pontos de auditoria
O que são “contratos” neste contexto
Contrato é qualquer acordo verificável entre camadas e times. Em SPAs seguras, contratos aparecem principalmente como: contrato de API (endpoints, payloads, códigos de erro), contrato de autenticação (como obter/renovar sessão, quais claims existem), contrato de autorização (como o back-end decide acesso), contrato de navegação (quais rotas existem e quais exigem autenticação) e contrato de observabilidade (quais eventos e logs existem para rastrear problemas).

Um contrato útil é específico e testável. Exemplo: “Ao receber 401, o front-end deve tentar refresh uma única vez; se falhar, deve limpar sessão e redirecionar para /login com returnUrl”. Isso é um contrato porque define comportamento, limites e resultado esperado.
Responsabilidades: separação clara para evitar brechas
Responsabilidade é a atribuição explícita de quem garante cada propriedade do sistema. Em autenticação e roteamento, uma fonte comum de falhas é assumir que “o outro lado” valida algo. Exemplo: o front-end pode esconder um botão de admin, mas isso não substitui a autorização no back-end. O checklist abaixo reforça responsabilidades típicas: o back-end é a fonte de verdade para autorização; o front-end é responsável por UX, fluxo de navegação, consistência de sessão e por não vazar dados sensíveis em UI/telemetria.
Pontos de auditoria: o que precisa ser verificável
Pontos de auditoria são itens que você consegue inspecionar e provar que estão corretos: testes automatizados, logs, evidências de configuração, revisões de código e validações de runtime. Uma auditoria eficaz não depende de “acreditar” que está certo; depende de evidências repetíveis.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
Checklist de contratos (front-end ↔ back-end)
1) Contrato de endpoints de autenticação
- Login: definir endpoint, método, payload, resposta e erros. Especificar se a resposta traz access token, refresh token, expiração e dados do usuário.
- Refresh: definir endpoint e regras de uso (quando chamar, quantas tentativas, se invalida refresh antigo).
- Logout: definir se é apenas local (front-end) ou se há revogação no servidor (blacklist, rotação, invalidação).
Ponto de auditoria: documentação de API (OpenAPI/Swagger ou equivalente) e testes de contrato (ex.: testes de integração que validem schema e status codes).
2) Contrato de status codes e formato de erro
Padronize como o back-end responde erros para que o front-end trate de forma consistente. Defina um envelope de erro com campos previsíveis (ex.: code, message, details, traceId). Diferencie claramente: 401 (não autenticado), 403 (autenticado sem permissão), 422 (validação), 429 (rate limit), 5xx (erro interno).
{ "error": { "code": "AUTH_INVALID", "message": "Credenciais inválidas", "details": [], "traceId": "b7f3..." }}Ponto de auditoria: testes automatizados garantindo que endpoints retornam o envelope definido e que o front-end não depende de mensagens livres para lógica.
3) Contrato de claims e identidade
- Definir quais claims existem e seus tipos (ex.: sub como string, roles como array).
- Definir se roles/permissões são estáticas no token ou se devem ser consultadas em endpoint de perfil.
- Definir como identificar tenant/organização (multi-tenant) e como isso impacta rotas e chamadas.
Ponto de auditoria: exemplos de tokens (redigidos) em documentação interna e testes que validem presença/ausência de claims obrigatórias.
4) Contrato de expiração, clock skew e renovação
Mesmo sem repetir estratégias já discutidas, aqui o foco é o contrato: qual é a duração do access token, do refresh token, qual tolerância de relógio (clock skew) é aceita e como o servidor se comporta em tokens expirados. Defina também se o refresh retorna um novo refresh token (rotação) e como o front-end deve armazenar/atualizar isso.
Ponto de auditoria: testes de integração simulando expiração e verificando que o servidor responde com códigos corretos e que o front-end segue o fluxo acordado.
5) Contrato de CORS, cookies e headers
- Definir origens permitidas, headers aceitos e expostos (ex.: Authorization, X-Request-Id).
- Se usar cookies, definir SameSite, Secure, HttpOnly e domínios.
- Definir se o back-end exige header de correlação (ex.: X-Request-Id) e se o front-end deve gerar quando ausente.
Ponto de auditoria: configuração do gateway/API e verificação via ferramentas (curl, Postman) e testes E2E.
Checklist de responsabilidades (o que cabe a cada camada)
Responsabilidades do back-end (fonte de verdade)
- Autenticar: validar credenciais, emitir tokens, validar refresh, aplicar rotação/revogação conforme política.
- Autorizar: checar permissões em cada endpoint sensível, independentemente do que o front-end mostra.
- Auditar: registrar eventos de segurança (login, refresh, logout, falhas, bloqueios) com correlação.
- Proteger dados: nunca retornar dados além do escopo permitido ao usuário.
Responsabilidades do front-end (UX, consistência e redução de risco)
- Orquestrar navegação: garantir que rotas exigidas não sejam acessíveis via UI sem sessão válida (mesmo que o back-end bloqueie).
- Gerenciar estado de sessão: manter UI consistente, evitar estados “meio logado”, lidar com transições e erros.
- Minimizar exposição: não logar tokens, não expor dados sensíveis em mensagens, não persistir além do necessário.
- Padronizar chamadas: centralizar cliente HTTP, anexar credenciais conforme contrato e tratar erros de forma uniforme.
Responsabilidades compartilhadas (precisam de acordo explícito)
- Modelo de permissões: nomes de roles/permissões, semântica e evolução (versionamento).
- Observabilidade: traceId, requestId, convenções de logs e métricas.
- Políticas de sessão: tempo de expiração, comportamento em inatividade e em múltiplos dispositivos.
Checklist de implementação no front-end (passo a passo prático)
Passo 1: consolidar um “Auth Contract” em código
Crie um módulo único que represente o contrato de autenticação: tipos, funções e mapeamento de erros. A meta é evitar que cada tela “interprete” respostas de um jeito diferente.
// auth.contract.ts (exemplo conceitual)export type AuthErrorCode = | 'AUTH_INVALID' | 'AUTH_EXPIRED' | 'AUTH_FORBIDDEN' | 'AUTH_RATE_LIMIT' | 'UNKNOWN';export type AuthResult = { accessToken: string; refreshToken?: string; expiresAt: number; user: { id: string; email: string; roles: string[]; };};export function mapAuthError(input: any): AuthErrorCode { const code = input?.error?.code; if (code === 'AUTH_INVALID') return 'AUTH_INVALID'; if (code === 'AUTH_EXPIRED') return 'AUTH_EXPIRED'; if (code === 'AUTH_FORBIDDEN') return 'AUTH_FORBIDDEN'; if (code === 'AUTH_RATE_LIMIT') return 'AUTH_RATE_LIMIT'; return 'UNKNOWN';}Ponto de auditoria: revisão de código garantindo que telas consomem apenas esse módulo para interpretar erros e que não há “ifs” espalhados por status code sem padrão.
Passo 2: padronizar o cliente HTTP com interceptores e correlação
Mesmo que a interceptação já exista, aqui o checklist foca em itens auditáveis: garantir que toda requisição tenha um identificador de correlação e que erros sejam normalizados para o restante do app.
- Gerar requestId quando não existir.
- Anexar headers exigidos pelo back-end.
- Normalizar erros em uma estrutura única (ex.: AppError).
// http.error.ts (exemplo conceitual)export type AppError = { kind: 'Network' | 'Http' | 'Auth' | 'Unknown'; status?: number; code?: string; message: string; traceId?: string; requestId?: string;};export function normalizeError(e: any): AppError { const status = e?.response?.status; const traceId = e?.response?.data?.error?.traceId; const code = e?.response?.data?.error?.code; if (!status) return { kind: 'Network', message: 'Falha de rede', traceId, code }; if (status === 401 || status === 403) return { kind: 'Auth', status, code, message: 'Acesso negado', traceId }; return { kind: 'Http', status, code, message: 'Erro na requisição', traceId };}Ponto de auditoria: busca no código por uso direto de fetch/axios fora do cliente padronizado; deve ser exceção justificada.
Passo 3: definir matriz de rotas × requisitos (documento vivo)
Crie uma matriz simples que liste cada rota e seus requisitos: autenticada? quais permissões? quais dados mínimos devem estar carregados? qual fallback? Isso evita “rotas esquecidas” e facilita QA.

- Rota
- Tipo: pública/autenticada
- Permissões/roles
- Dependências de dados (ex.: perfil carregado)
- Comportamento em 401/403
Ponto de auditoria: a matriz deve bater com a configuração real de rotas e com os testes E2E (um teste por linha crítica).
Passo 4: padronizar estados de carregamento e transições de sessão
Checklist de UI para evitar vazamento de conteúdo e “flash” de telas indevidas:
- Enquanto a sessão está sendo reidratada/verificada, mostrar um estado neutro (skeleton/loader) sem dados sensíveis.
- Evitar renderizar componentes de área autenticada antes de confirmar estado.
- Em falha de sessão, limpar caches em memória relacionados ao usuário (queries, stores) antes de redirecionar.
Ponto de auditoria: testes E2E simulando reload com sessão expirada e verificando que não há flash de conteúdo protegido.
Passo 5: mapear eventos de segurança e telemetria (sem dados sensíveis)
Defina quais eventos o front-end registra (para analytics/observabilidade) e quais campos são proibidos. Eventos típicos: login_succeeded, login_failed, token_refresh_failed, access_denied_view, session_expired. Campos proibidos: tokens, senhas, payloads completos de erro com PII.
// security.events.ts (exemplo conceitual)type SecurityEvent = { name: 'login_succeeded' | 'login_failed' | 'session_expired' | 'access_denied_view'; at: number; requestId?: string; traceId?: string; meta?: { reason?: string; route?: string; status?: number; };};export function trackSecurityEvent(evt: SecurityEvent) { // enviar para sua ferramenta de logs/telemetria // garantir redaction de campos sensíveis}Ponto de auditoria: revisão de logs em ambiente de teste garantindo que não há tokens/PII; checagem automática via lint/regex em pipelines (quando aplicável).
Passo 6: checklist de cache e invalidação (dados do usuário)
Se você usa cache de dados (ex.: React Query, SWR ou cache próprio), defina responsabilidades claras:
- Ao logout: invalidar queries do usuário, limpar dados em memória e resetar stores.
- Ao trocar de usuário na mesma máquina: garantir que não há “vazamento” de dados do usuário anterior.
- Ao receber 403 em um recurso: decidir se isso invalida permissões locais e se deve reconsultar perfil.
Ponto de auditoria: teste manual guiado e teste E2E: login com usuário A, navegar em páginas com dados, logout, login com usuário B e verificar ausência de dados do A.
Passo 7: checklist de versionamento e compatibilidade
Defina como o front-end reage quando o back-end muda contrato:
- Versionamento de API (path, header ou semântico).
- Feature flags para mudanças graduais.
- Fallback para campos ausentes (ex.: roles não presente).
Ponto de auditoria: testes de contrato em CI e validação de schema (ex.: zod/io-ts) para respostas críticas, com tratamento de erro controlado.
Checklist de auditoria técnica (o que revisar no código e no pipeline)
1) Auditoria de código: itens rastreáveis
- Não existem tokens em logs, console, mensagens de erro ou analytics.
- Não existem chamadas HTTP fora do cliente padronizado (ou estão justificadas).
- Rotas protegidas têm requisitos explícitos (mapeados na matriz) e testes cobrindo cenários 401/403.
- Componentes sensíveis não renderizam dados antes de estado de sessão confirmado.
- Tratamento de erro é consistente e não depende de strings de mensagem.
2) Auditoria de dependências e build
- Dependências atualizadas e com política de correção (ex.: alertas de vulnerabilidade tratados).
- Build reproduzível e com variáveis de ambiente controladas (sem segredos no bundle).
- Source maps: política definida por ambiente (ex.: restrições em produção) e sem expor segredos.
Ponto de auditoria: relatório de dependências (SCA), verificação de variáveis de ambiente e inspeção do bundle para strings sensíveis.
3) Auditoria de configuração de ambiente
- URLs de API por ambiente (dev/staging/prod) e validação para evitar apontar produção em builds de teste.
- Política de CORS e domínios autorizados alinhados com o contrato.
- Headers de segurança relevantes no servidor que entrega a SPA (ex.: CSP, HSTS quando aplicável), com validação via scanner.
Ponto de auditoria: checklist de deploy com evidências (prints/config export) e varredura automatizada em staging.
Checklist de QA e testes (cenários mínimos)
1) Cenários de autenticação e sessão
- Login válido e inválido (mensagens e estados corretos).
- Expiração de sessão durante navegação (UI consistente, sem loops).
- Refresh falhando (comportamento acordado: limpar sessão e redirecionar).
- Troca de usuário sem vazamento de dados.
2) Cenários de autorização
- Usuário sem permissão acessando rota protegida: recebe 403 e vê tela adequada.
- Usuário com permissão: acesso normal.
- Permissão removida no servidor durante sessão: front-end reage ao 403 sem manter UI indevida.
3) Cenários de navegação e deep link
- Acesso direto por URL em rota autenticada sem sessão: redireciona conforme contrato.
- Retorno ao fluxo após login (returnUrl) respeitando regras de segurança (ex.: bloquear redirecionamento externo).
- 404 em rotas inexistentes sem vazar detalhes.
Ponto de auditoria: suíte E2E com evidências (relatórios) e casos mapeados à matriz de rotas × requisitos.
Checklist de governança: como manter o contrato vivo
1) Donos (owners) e revisão obrigatória
- Definir owner do contrato de autenticação (normalmente back-end + segurança) e do cliente HTTP (front-end).
- PRs que alterem endpoints/claims exigem atualização do documento de contrato e testes.
- Revisão obrigatória de segurança para mudanças em login/refresh/logout e em rotas sensíveis.
2) Mudanças controladas e comunicação
- Changelog de API e de claims.
- Janela de compatibilidade (ex.: manter campo antigo por X versões).
- Ambiente de staging com dados e permissões representativas para validar cenários reais.
3) Evidências mínimas para auditoria interna
- Documento de contrato (API + autenticação + erros) com versão.
- Matriz de rotas × requisitos atualizada.
- Relatórios de testes (unitários/integrados/E2E) cobrindo 401/403/expiração.
- Relatório de dependências e verificação de ausência de segredos no bundle.