3 Auth
Rafael Lopes edited this page 2026-05-29 12:22:37 -03:00

Modulo de Autenticacao

Visao geral

O modulo auth centraliza login, emissao de JWT, validacao de token, autorizacao por perfil e sincronizacao do usuario autenticado com o banco do Omnichannel.

Provedores implementados:

  • LDAP / Active Directory: login com usuario e senha corporativos.
  • Microsoft OAuth / Entra ID: login via conta Microsoft.

Depois que o provedor confirma a identidade, o backend emite um JWT proprio da aplicacao. Esse token deve ser enviado pelo frontend em todas as rotas privadas usando:

Authorization: Bearer <token>

Estrutura de arquivos

src/modules/auth/
|-- auth.module.ts
|-- auth.controller.ts
|-- auth.service.ts
|-- auth.config.ts
|-- auth-token.service.ts
|-- auth.types.ts
|-- user-access.service.ts
|-- decorators/
|   |-- public.decorator.ts
|   `-- roles.decorator.ts
|-- dto/
|   `-- login.dto.ts
|-- guards/
|   |-- jwt-auth.guard.ts
|   `-- roles.guard.ts
|-- providers/
|   |-- ldap-auth.provider.ts
|   |-- microsoft-oauth.provider.ts
|   `-- oauth-state.service.ts
`-- repositories/
    `-- user-access.repository.ts

Responsabilidades principais:

  • AuthController: expoe rotas publicas de login e OAuth.
  • AuthService: fachada que delega para LDAP ou Microsoft.
  • AuthTokenService: emite e valida JWT.
  • JwtAuthGuard: exige Bearer token nas rotas privadas.
  • RolesGuard: valida perfis com @Roles().
  • UserAccessService: regra de sincronizacao do usuario autenticado.
  • UserAccessRepository: instrucoes SQL do fluxo de acesso.
  • LoginDto: validacao formal do payload de login.

Rotas publicas

As rotas abaixo nao exigem JWT:

Metodo Rota Descricao
GET /health Health check da API
GET /auth/config Informa provedores de login habilitados
POST /auth/login Login LDAP/AD
GET /auth/oauth/microsoft/start Inicia login Microsoft
GET /auth/oauth/microsoft/callback Recebe callback Microsoft

Todas as demais rotas HTTP exigem JWT valido.


Rotas privadas e perfis

O JwtAuthGuard foi registrado como guard global. Isso significa que toda rota e privada por padrao, exceto as marcadas com @Public().

Exemplo:

@Public()
@Get('config')
getConfig() {}

Para autorizacao por perfil, o backend usa @Roles():

@Roles('Admin')
@Get('users')
listUsers() {}

Regras atuais:

  • Admin: acessa administracao, usuarios, areas, base de conhecimento e configuracoes sensiveis.
  • Supervisor: acessa visoes operacionais liberadas para supervisao.
  • Agente: acessa fluxos autenticados sem permissao administrativa.

Fluxo LDAP / Active Directory

Frontend
  -> POST /auth/login { username, password }
  -> LoginDto valida payload
  -> AuthController
  -> AuthService.loginWithLdap()
  -> LdapAuthProvider.authenticate()
      -> valida se LDAP esta habilitado
      -> conecta no servidor LDAP
      -> faz bind com usuario e senha
      -> busca dados do usuario no diretorio, se configurado
      -> monta AuthenticatedUser
  -> UserAccessService.syncAuthenticatedUser()
      -> UserAccessRepository executa SQL
      -> cria/atualiza usuarios
      -> cria/atualiza usuarios_provedores
      -> carrega perfis e areas
  -> AuthTokenService.issueToken()
  -> retorna { token, user }

O erro retornado ao usuario continua generico (Autenticacao falhou). O erro real e registrado no log interno do provider para diagnostico sem vazar detalhes sensiveis.


Fluxo Microsoft OAuth

Frontend
  -> GET /auth/oauth/microsoft/start
Backend
  -> gera state assinado com HMAC-SHA256 usando JWT_SECRET
  -> redireciona para Microsoft
Usuario
  -> autentica na Microsoft
Microsoft
  -> chama /auth/oauth/microsoft/callback?code=...&state=...
Backend
  -> valida state
  -> troca code por access_token
  -> consulta Microsoft Graph /me
  -> sincroniza usuario no banco
  -> emite JWT da aplicacao
  -> redireciona para o frontend com payload no fragmento da URL
Frontend
  -> le #auth=...
  -> salva sessao em sessionStorage
  -> limpa a URL

O token nao e mais enviado em query string. Ele vai no fragmento #auth=..., que nao e enviado ao servidor em requisicoes HTTP e e removido pelo frontend apos processamento.


JWT da aplicacao

Payload principal:

{
  "sub": "4",
  "name": "Nome Completo",
  "email": "usuario@empresa.com",
  "provider": "ldap",
  "username": "usuario",
  "perfis": ["Admin"],
  "profiles": ["Admin"],
  "areas": ["Suporte"],
  "areaPrincipal": "Suporte",
  "accessStatus": "assigned"
}

O sub usa o ID interno da tabela usuarios.

O token e:

  • assinado com JWT_SECRET;
  • emitido com expiracao definida por JWT_EXPIRES_IN;
  • validado em todas as rotas privadas;
  • enviado pelo frontend como Bearer token.

Sessao no frontend

O frontend armazena authToken e authUser em sessionStorage, nao em localStorage.

Motivo:

  • reduz persistencia indevida apos fechar o navegador;
  • evita reaproveitamento de sessoes antigas salvas localmente;
  • continua simples para o modelo atual do produto.

Observacao: uma alternativa ainda mais forte para producao seria cookie HttpOnly + Secure + SameSite, mas exigiria ajuste maior no fluxo do frontend e no CORS.


WebSocket WhatsApp

O namespace Socket.IO /whatsapp tambem exige JWT no handshake.

O frontend envia:

io(WHATSAPP_SOCKET_URL, {
  auth: {
    token: getAuthToken()
  }
});

Sem token valido, o socket nao conecta e nao recebe QR Code, status ou mensagens.


Rate limit

O backend usa @nestjs/throttler com limite global configuravel:

RATE_LIMIT_TTL_MS=60000
RATE_LIMIT_MAX=300

Padrao atual: 300 requisicoes por IP a cada 60 segundos.


Variaveis de ambiente

FRONTEND_URL=http://localhost:3000
JWT_SECRET=uma-chave-longa-e-aleatoria
JWT_EXPIRES_IN=8h

RATE_LIMIT_TTL_MS=60000
RATE_LIMIT_MAX=300

AUTH_PROVIDERS=ldap,microsoft

LDAP_ENABLED=true
LDAP_URL=ldaps://servidor-ad:636
LDAP_DOMAIN=empresa.com.br
LDAP_USER_DN_TEMPLATE={{username}}@empresa.com.br
LDAP_SEARCH_BASE=DC=empresa,DC=com
LDAP_SEARCH_FILTER=(&(objectClass=user)(sAMAccountName={{username}}))
LDAP_TIMEOUT_MS=5000

MICROSOFT_ENABLED=false
MICROSOFT_TENANT_ID=common
MICROSOFT_CLIENT_ID=
MICROSOFT_CLIENT_SECRET=
MICROSOFT_REDIRECT_URI=http://localhost:3001/auth/oauth/microsoft/callback
MICROSOFT_SUCCESS_REDIRECT_URL=http://localhost:3000/login

JWT_SECRET deve ser forte e exclusivo por ambiente.


Diagnostico

Login LDAP falha

  • Verifique LDAP_URL, LDAP_DOMAIN e LDAP_USER_DN_TEMPLATE.
  • Confirme conectividade do backend com o AD.
  • Verifique se LDAP_SEARCH_BASE e LDAP_SEARCH_FILTER batem com o diretorio.
  • Consulte logs do backend; o provider registra o motivo interno sem expor para o usuario.

Token invalido ou expirado

  • Verifique se o frontend esta enviando Authorization: Bearer <token>.
  • Verifique se JWT_SECRET nao mudou depois da emissao do token.
  • Faca login novamente para renovar a sessao.

Usuario autenticado cai como unassigned

  • O login funcionou, mas faltam perfil/area no banco.
  • Um Admin deve atribuir perfil e area para o usuario.

Microsoft OAuth falha

  • Verifique MICROSOFT_REDIRECT_URI no Azure e no .env.
  • Confirme MICROSOFT_CLIENT_ID e MICROSOFT_CLIENT_SECRET.
  • Refaca o fluxo se o state expirar.

Estado atual

  • Login LDAP/AD
  • Login Microsoft OAuth
  • State OAuth assinado
  • JWT emitido pela aplicacao
  • JWT validado nas rotas privadas
  • Roles no backend
  • Bearer token no frontend
  • Token fora de query string no OAuth
  • WebSocket WhatsApp protegido por token
  • SQL de acesso isolado em repository
  • DTO e ValidationPipe no login
  • Rate limit global
  • Auditoria formal de login em tabela propria
  • Cookie HttpOnly como alternativa futura ao sessionStorage