# 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 = ''` 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)