Files
SeConectai_Vendas/Etapas/02-autenticacao-rls.md
T
2026-08-14 17:35:24 -03:00

5.5 KiB

Etapa 2/8 — Autenticação, Autorização e Row Level Security

Contexto do projeto

Continuação do SeConectai Vendas (CRM/vendas multi-tenant). A Etapa 1 já entregou: projeto NestJS + Docker Compose + Postgres/Prisma com o schema completo migrado (incluindo as tabelas master_admins, tenant_users, auth_refresh_tokens, password_reset_tokens, login_attempts e as policies de RLS).

Existem dois tipos de usuário:

  • master_admins: você, dono da plataforma — acesso a todos os tenants.
  • tenant_users: usuários de cada tenant (cliente seu), com papéis (tenant_admin, vendedor, financeiro, visualizador), restritos aos próprios dados via RLS.

Objetivo desta etapa

Implementar login, emissão/renovação de tokens, reset de senha, mecanismo de definição do tenant_id da sessão no Postgres (RLS) e proteção contra força bruta — para ambos os tipos de usuário.

Tarefas

  1. Módulo de autenticação (src/modules/auth/)

    • POST /auth/master/login — email + senha → valida contra master_admins.senha_hash (argon2id) → retorna access token (JWT, expiração curta, ex: 15 min) + refresh token (opaco, guardado como hash em auth_refresh_tokens, expiração longa, ex: 30 dias).
    • POST /auth/tenant/login — email + senha + (implícito) tenant resolvido pelo email único dentro do tenant → mesma lógica, usando tenant_users.
    • POST /auth/refresh — recebe refresh token, valida hash e expiração/revogação, rotaciona (invalida o antigo, emite um novo) e retorna novo par de tokens.
    • POST /auth/logout — revoga o refresh token atual.
    • POST /auth/password/forgot — gera token em password_reset_tokens (hash, expiração curta, ex: 1h) e dispara e-mail (por ora, apenas logar o link/token no console — o envio real de e-mail é de uma etapa futura).
    • POST /auth/password/reset — valida token, atualiza senha_hash, marca token como usado, revoga todos os refresh tokens ativos do usuário.
  2. JWT payload

    • Incluir no access token: sub (id do usuário), tipo (master|tenant_user), tenant_id (null para master), role (para tenant_user).
    • Implementar JwtStrategy (Passport) validando assinatura e expiração.
  3. Guards e decorators

    • @CurrentUser() — decorator para extrair o usuário autenticado do request.
    • MasterGuard — permite apenas tipo === 'master'.
    • TenantGuard — permite apenas tipo === 'tenant_user', e injeta tenant_id no contexto da request.
    • RolesGuard + @Roles('tenant_admin', ...) — restringe endpoints por papel dentro do tenant.
  4. Aplicação do RLS via Prisma

    • Implementar um mecanismo (middleware/interceptor do Nest, executado por request) que, para requests autenticadas como tenant_user, abre uma transação Prisma e executa SET LOCAL app.current_tenant_id = '<tenant_id>' antes de qualquer query — garantindo que a policy de RLS do Postgres filtre os dados automaticamente.
    • Para requests como master, usar uma conexão/role de banco com BYPASS ROW LEVEL SECURITY (criar essa role na migration, se ainda não existir, com CREATE ROLE app_master BYPASSRLS LOGIN ... — documentar isso no .env.example como uma segunda connection string opcional, DATABASE_URL_MASTER).
    • Escrever um teste de integração que prove o isolamento: criar dois tenants, um usuário em cada, confirmar que a query de um nunca retorna dado do outro mesmo manipulando o tenant_id de outras formas (ex: tentando passar um tenant_id diferente no body de uma requisição — o tenant_id da sessão deve sempre vir do token, nunca de input do usuário).
  5. Proteção contra força bruta

    • Toda tentativa de login (sucesso ou falha) grava em login_attempts.
    • Após N tentativas falhas (configurável, ex: 5) para o mesmo e-mail em uma janela de tempo (ex: 15 min), bloquear novas tentativas com 429 e mensagem clara, mesmo que a senha esteja correta.
    • Rate limiting geral no endpoint de login (ex: @nestjs/throttler).
  6. Segurança de senha

    • Hash com argon2id (biblioteca argon2), parâmetros de custo documentados no código.
    • Validação de força mínima da senha no cadastro/reset (tamanho mínimo, não permitir senhas triviais).
    • Refresh tokens e reset tokens nunca armazenados em texto puro — sempre hash (ex: sha256) antes de gravar no banco.

Critérios de aceite

  • Login master e login tenant funcionam e retornam access+refresh token válidos
  • Refresh token rotaciona corretamente; token antigo usado após rotação é rejeitado
  • Logout revoga o refresh token
  • Fluxo de esqueci minha senha gera token, valida expiração/uso único
  • MasterGuard e TenantGuard bloqueiam corretamente rotas erradas (testar com token de tenant tentando acessar rota master e vice-versa)
  • RolesGuard bloqueia usuário vendedor tentando acessar rota restrita a tenant_admin
  • Teste de integração prova isolamento entre tenants via RLS (dado de um tenant nunca vaza para outro, mesmo forçando tenant_id no payload da requisição)
  • Após 5 tentativas de login falhas, novas tentativas são bloqueadas temporariamente
  • Todas as senhas no banco estão como hash argon2id (nenhuma em texto puro em nenhuma tabela)