Skip to content

Arquitetura de Autenticação

Este documento descreve a arquitetura de autenticação e autorização do Neemias, abrangendo o fluxo completo de login, tokens, sessões e proteção de rotas.

Visão geral

A autenticação é baseada em tokens de acesso JWT de curta duração combinados com tokens de atualização (refresh) de longa duração com rotação. O backend (Cloudflare Workers) gerencia a criação, validação e revogação de sessões. O frontend (React SPA) consome os tokens e mantém a sessão local em IndexedDB.

Tokens e durações

TokenAlgoritmoTTLArmazenamento
Access TokenJWT HS256 (jose)15 minutosMemória + IndexedDB (frontend)
Refresh TokenOpaco (hash SHA-256 armazenado)7 diasauth_refresh_sessions (backend), IndexedDB (frontend)
CSRF TokenOpacoVinculado à sessãoIndexedDB (frontend), enviado como X-CSRF-Token

Fluxo de autenticação

1. Login

POST /api/v1/auth/login  { email, password }
  1. Frontend envia email e password para o backend.
    • Se o usuário digitar um identificador curto (admin, chamador, relatorios, cadastro), o frontend normaliza para o e-mail correspondente (admin@neemias.local, etc.).
  2. Backend valida a senha usando PBKDF2 (100.000 iterações, SHA-256).
    • Formato do hash: pbkdf2:<hexSalt>:<hexHash>.
  3. Backend cria uma sessão de autenticação:
    • Gera refresh token (opaco).
    • Armazena hash SHA-256 do refresh token em auth_refresh_sessions.
    • Gera CSRF token vinculado à sessão.
    • Assina access token JWT HS256 com payload: userId, role, sessionId, csrfToken.
  4. Backend retorna:
    • accessToken
    • accessTokenExpiresAt
    • refreshToken
    • csrfToken
    • user (payload com userId, displayName, role, status)
  5. Frontend persiste os metadados da sessão em IndexedDB (sessions table) e os dados do usuário em users.

2. Requisições autenticadas

Toda requisição autenticada deve incluir:

HeaderObrigatórioDescrição
Authorization: Bearer <accessToken>SimToken JWT de acesso
X-Device-IdSimIdentificador do dispositivo (obrigatório em todas as requisições)
X-CSRF-TokenSim (cookie mode)Token CSRF para rotas de mutação quando AUTH_SESSION_MODE=cookie
Idempotency-KeySim (mutações)Chave de idempotência para POST/PATCH

3. Refresh (rotação de tokens)

POST /api/v1/auth/refresh  { refreshToken }
  1. Frontend detecta access token expirado (ou próximo da expiração) e chama o endpoint de refresh.
  2. Backend valida o hash do refresh token em auth_refresh_sessions.
  3. Backend aplica rotação de refresh token:
    • Revoga o refresh token anterior (revoked_at, rotated_at).
    • Cria novo par access/refresh.
    • Registra replaced_by apontando para a nova sessão.
  4. Frontend substitui os tokens locais pelos novos.

Detecção de reuso malicioso: Se um refresh token já revogado for reutilizado, o backend detecta e invalida toda a cadeia de sessões do usuário.

4. Revogação

POST /api/v1/auth/revoke  { refreshToken }

Revoga explicitamente uma sessão, marcando revoked_at em auth_refresh_sessions.

5. Validação de sessão

POST /api/v1/session/validate

Verifica se a sessão atual está ativa e retorna o estado. Usado pelo frontend para validação periódica.

Modo de desenvolvimento (Dev Mode)

Quando AUTH_MODE=dev está configurado no backend:

  • Tokens fixos pré-configurados em variáveis de ambiente são aceitos.
  • Não é necessário JWT real.
  • Facilita o desenvolvimento local e testes.

Importante: Em produção, AUTH_MODE=jwt é obrigatório (ver Production Readiness Gates).

Hashing de senha

  • Algoritmo: PBKDF2 (Password-Based Key Derivation Function 2).
  • Iterações: 100.000.
  • Hash: SHA-256.
  • Formato de armazenamento: pbkdf2:<hexSalt>:<hexHash>.
  • Histórico: O backend legado usava scrypt, que se mostrou incompatível com o ambiente Cloudflare Workers. A migração para PBKDF2 foi resolvida na ADR-0003.

Modos de sessão

ModoConfiguraçãoComportamento
BearerAUTH_SESSION_MODE=bearer (padrão)Refresh token enviado no corpo da resposta; frontend armazena em IndexedDB
CookieAUTH_SESSION_MODE=cookieRefresh token em cookie httpOnly; mutações exigem X-CSRF-Token

Arquitetura de módulos

Backend (workers/src/)

ArquivoResponsabilidade
modules/auth/password.tsHashing e verificação PBKDF2
modules/auth/sessionTokens.tsAssinatura/verificação JWT + refresh token
middleware/auth.tsMiddleware de verificação JWT + dev mode + role guard
db/queries.tsQueries reutilizáveis de auth e idempotência
routes/auth.tsHandlers de login, refresh, revoke

Frontend (app/src/)

ArquivoResponsabilidade
app/context/AuthContext.tsxEstado de autenticação, papéis, sessão
modules/auth/backendAuth.tsModo de autenticação via backend
modules/auth/sessionManager.tsGerenciamento de sessão local
modules/auth/sessionHydrator.tsHidratação da sessão a partir do IndexedDB
modules/auth/keyRotationService.tsRotação de chaves de criptografia local

Diagrama de sequência

┌──────────┐         ┌──────────┐         ┌──────────────┐
│ Frontend │         │ Backend  │         │ D1 (SQLite)  │
└────┬─────┘         └────┬─────┘         └──────┬───────┘
     │                    │                      │
     │  POST /auth/login  │                      │
     │───────────────────▶│                      │
     │                    │  SELECT password_hash│
     │                    │─────────────────────▶│
     │                    │◀─────────────────────│
     │                    │                      │
     │                    │  PBKDF2.verify()     │
     │                    │                      │
     │                    │  INSERT session      │
     │                    │─────────────────────▶│
     │                    │◀─────────────────────│
     │                    │                      │
     │  { accessToken,    │                      │
     │    refreshToken,   │                      │
     │    csrfToken,      │                      │
     │    user }          │                      │
     │◀───────────────────│                      │
     │                    │                      │
     │  (15 min depois)   │                      │
     │                    │                      │
     │  POST /auth/refresh│                      │
     │───────────────────▶│                      │
     │                    │  SELECT/UPDATE       │
     │                    │  session (rotate)    │
     │                    │─────────────────────▶│
     │                    │◀─────────────────────│
     │                    │                      │
     │  { newAccessToken, │                      │
     │    newRefreshToken }│                     │
     │◀───────────────────│                      │
     │                    │                      │
     │  POST /auth/revoke │                      │
     │───────────────────▶│                      │
     │                    │  UPDATE revoked_at   │
     │                    │─────────────────────▶│
     │                    │◀─────────────────────│
     │  { ok: true }      │                      │
     │◀───────────────────│                      │

Decisões arquiteturais relacionadas

  • ADR-0003: Auth Adapter and Session Token Model: Modelo de sessão com access token de curta duração, sessão local com TTL, e bloqueio de ações protegidas após expiração. Define que a implementação de auth deve ser encapsulada atrás de uma interface de módulo.
  • ADR-0007: Keycloak token validation boundary: Backend valida tokens Bearer via JWKS e verificações de issuer/audience. Frontend mantém detalhes específicos do provedor dentro dos limites do adapter de auth.

Fontes: workers/CONTEXT.md, ADR-0003, ADR-0007

Distribuído sob licença MIT.