Backend NestJS de referência: auth pensada pra produtos de verdade
Como o template NestJS de referência trata login social, Active Directory, Argon2id e OAuth que se comporta bem no mobile — pra times que precisam de um ponto de partida sólido, não só uma demo que funciona com Google.
Se você está começando uma API NestJS e já sabe que autenticação vai ser mais do que "e-mail + senha + talvez Google", provavelmente já caiu na mesma armadilha: semanas ligando provedor OAuth, LDAP pro cliente corporativo, hash de senha que não vai te envergonhar depois, e deep link que quebra dentro do navegador mobile.
Esse é o público desta atualização do meu backend NestJS de referência. O post de julho focou em ops — Compose, Graylog, health checks, documentação ao lado do Swagger. Este foca em auth que você liga sob demanda: provedores de identidade social, Active Directory on-prem, hashing mais seguro e fluxos OAuth que se comportam bem no mobile.
Demo ao vivo: nest.lacorte.dev · Visão do projeto: /projects/nestjs-backend · Código: GitHub
Pra quem isso ajuda
O template pode ser útil se você:
- Precisa de um app NestJS 11 pronto pra clonar com REST e GraphQL já no Fastify
- Espera mais de um login social (produto, portal B2B, app de comunidade ou white-label)
- Tem stakeholder enterprise pedindo Active Directory (LDAP/LDAPS) e roles ligadas a security groups
- Entrega um cliente mobile ou Expo e precisa concluir OAuth sem gambiarra frágil de redirect
- Quer cada provedor documentado pra ligar e desligar recurso sem engenharia reversa no repo
Continua sendo uma referência. Apague o que não for usar. O objetivo é um padrão claro por provedor — não uma dependência permanente de todos os IdPs da lista.
Login social como módulos opt-in
O template inclui strategies e rotas Passport pra provedores comuns, entre eles Google, Facebook, X/Twitter (PKCE), GitHub, Figma, LinkedIn, Slack, Atlassian, GitLab, Bitbucket, Discord, Twitch, Amazon, Patreon, Dropbox, Reddit, Apple (callback form_post), Steam OpenID e MetaMask SIWE.
Cada provedor costuma seguir o mesmo formato:
- Módulo de config e flags de env (por exemplo
GITHUB_AUTH_ENABLED, client id/secret, callback URL, allowlist de redirect, roles padrão) - Par strategy + guard
- Rotas
GET /auth/<provider>e callback em/api/v1 - Campo de vínculo no user (
githubId,appleId, …) - Guia na wiki em /auth/social
Pra clientes mobile e SPA, POST /auth/exchange (OauthExchangeService) troca um código de curta duração por tokens — assim você não precisa enfiar JWT em deep link.
Conselho prático: ligue só os provedores que você vai configurar no ambiente. Strategies não usadas ficam fora do caminho quando a flag *_AUTH_ENABLED está desligada. Provedores que não valiam a manutenção saíram da árvore pra clones não herdarem código morto.
Active Directory com mapeamento grupo → role
Piloto corporativo costuma começar com "dá pra logar com AD?" e depois pede roles alinhadas aos security groups que já existem. O template cobre esse caminho.
- Endpoint:
POST /auth/ad/login - Serviço:
ActiveDirectoryLdapService - Guias: Active Directory, além das páginas LDAP / LDAPS
No login, o serviço pode ler memberOf, mapear grupos pra roles da aplicação (super, admin, manager, user) via AD_LDAP_GROUP_ROLE_MAP e, opcionalmente, sincronizar essas roles a cada login AD bem-sucedido (AD_LDAP_SYNC_ROLES_ON_LOGIN).
# Exemplo — ajuste DNs e segredos ao seu diretório; isto não é política de produção
AD_LDAP_ENABLED=true
AD_LDAP_URL=ldaps://dc.example.com:636
AD_LDAP_BASE_DN=DC=example,DC=com
AD_LDAP_BIND_DN=CN=NestBind,OU=Service,DC=example,DC=com
AD_LDAP_BIND_PASSWORD=replace-me
AD_LDAP_DEFAULT_ROLES=user
AD_LDAP_GROUP_ROLE_MAP='CN=Nest-Admins,OU=Groups,DC=example,DC=com|admin;Nest-Managers|manager;Nest-Users|user'
AD_LDAP_SYNC_ROLES_ON_LOGIN=trueSe o mapa estiver vazio, usuários novos ainda recebem AD_LDAP_DEFAULT_ROLES. Se o mapa estiver errado, as roles ficam erradas — trate o mapeamento como configuração revisada com quem é dono do AD.
Hash de senha com Argon2id
Contas locais usam argon2id via password.util.ts, com parâmetros de custo ajustáveis:
{
memoryCost: parsePositiveInt(process.env.ARGON2_MEMORY_COST, 19456),
timeCost: parsePositiveInt(process.env.ARGON2_TIME_COST, 2),
parallelism: parsePositiveInt(process.env.ARGON2_PARALLELISM, 1),
}isPasswordHashed reconhece encodings padrão de Argon2. Se você forkar o template em cima de uma tabela de users já em bcrypt, planeje uma migração — os defaults servem pra projeto do zero ou upgrade deliberado, não pra reescrever em silêncio todo hash armazenado.
Fastify e redirects OAuth confiáveis
A stack HTTP roda em Fastify (@nestjs/platform-fastify), incluindo o driver Apollo GraphQL e o suporte a sessão necessário pro PKCE do Twitter (@fastify/cookie, @fastify/session, @fastify/passport).
Um modo comum de falha com Expo AuthSession e Chrome Custom Tabs é o redirect do cliente ganhar um # vazio no final. Em vez de depender só de um 302 Location cru, o template conclui o hop do navegador com uma página HTML pequena que chama location.replace() numa URL limpa (sendOAuthClientRedirect / stripTrailingEmptyHash):
export function sendOAuthClientRedirect(
reply: AppReply,
redirectUrl: string,
): void {
const cleanUrl = stripTrailingEmptyHash(redirectUrl);
const html =
`<!DOCTYPE html><html><head><meta charset="utf-8">` +
`<meta http-equiv="refresh" content="0;url=${escapeHtmlAttribute(cleanUrl)}">` +
`<script>window.location.replace(${JSON.stringify(cleanUrl)});</script>` +
`</head><body></body></html>`;
reply
.status(200)
.header('Content-Type', 'text/html; charset=utf-8')
.header('Cache-Control', 'no-store')
.send(html);
}Esse detalhe importa se os primeiros usuários estão no celular, não no Postman.
Documentação ao lado da API
Auth só é útil se a próxima pessoa conseguir configurar sem escavação no Slack. A wiki embutida cobre o índice social e os fluxos de AD em inglês e português brasileiro. O README está em inglês e aponta pros mesmos caminhos. O Swagger continua em /swagger na mesma origem da documentação.
Como começar
- Visão geral: nest.lacorte.dev
- Guias de login social: nest.lacorte.dev/auth/social
- Active Directory: nest.lacorte.dev/auth/active-directory
- API interativa: nest.lacorte.dev/swagger
- Página do produto neste site: /projects/nestjs-backend
- Clone: github.com/mateuslacorte/nestjs-backend
Sobe a stack com Compose, confirma /health, liga os provedores de auth que precisa e remove o resto. O boilerplate existe pra você gastar tempo no produto — não pra reimplementar o mesmo OAuth e AD em cada Nest novo.
Comentários
Vai direto ao ponto — dúvidas, correções e causos de produção são bem-vindos.
Carregando comentários…