Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

OpenID Connect no Node.js: login seguro com OIDC

Atualizado em: 29 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

OpenID Connect no Node.js adiciona uma camada de identidade ao OAuth 2.0. Enquanto OAuth autoriza acesso a recursos, OpenID Connect permite que uma aplicação autentique o usuário e receba informações verificáveis em um ID Token.

O fluxo recomendado para aplicações web modernas é Authorization Code com PKCE. A aplicação redireciona o usuário ao provedor, recebe um código curto, troca esse código no backchannel e valida rigorosamente o ID Token.

Conceitos principais

  • Authorization Server ou OpenID Provider: autentica o usuário;
  • Client: aplicação Node.js;
  • ID Token: JWT com dados da autenticação;
  • Access Token: credencial para APIs;
  • UserInfo: endpoint opcional de atributos;
  • Discovery: documento com endpoints e capacidades.

Discovery

O provedor publica:

https://issuer.example/.well-known/openid-configuration

O documento informa issuer, authorization endpoint, token endpoint, JWKS URI e algoritmos suportados. Valide o issuer esperado e use HTTPS.

Authorization Code com PKCE

Gere valores criptograficamente aleatórios:

import crypto from 'node:crypto';

const state = crypto.randomBytes(32).toString('base64url');
const nonce = crypto.randomBytes(32).toString('base64url');
const codeVerifier = crypto.randomBytes(64).toString('base64url');
const codeChallenge = crypto
  .createHash('sha256')
  .update(codeVerifier)
  .digest('base64url');

Armazene state, nonce e codeVerifier na sessão temporária vinculada ao navegador.

Redirecionamento

const url = new URL(metadata.authorization_endpoint);
url.searchParams.set('client_id', clientId);
url.searchParams.set('response_type', 'code');
url.searchParams.set('redirect_uri', redirectUri);
url.searchParams.set('scope', 'openid profile email');
url.searchParams.set('state', state);
url.searchParams.set('nonce', nonce);
url.searchParams.set('code_challenge', codeChallenge);
url.searchParams.set('code_challenge_method', 'S256');

Use redirect URIs fixas e previamente cadastradas. Não aceite uma URL arbitrária do cliente.

Callback

Compare o state em tempo constante quando possível e use-o uma única vez. Depois, troque o código:

const body = new URLSearchParams({
  grant_type: 'authorization_code',
  client_id: clientId,
  code,
  redirect_uri: redirectUri,
  code_verifier: codeVerifier
});

const response = await fetch(metadata.token_endpoint, {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  body,
  signal: AbortSignal.timeout(5000)
});

Clientes confidenciais também autenticam no token endpoint conforme o método registrado.

Validando o ID Token

Valide:

  • assinatura com chave do JWKS;
  • iss exatamente igual ao issuer;
  • aud contendo o client ID;
  • azp quando houver múltiplas audiences;
  • exp e iat;
  • nonce igual ao salvo;
  • algoritmo permitido;
  • auth_time quando exigido.

Não aceite alg escolhido livremente pelo token.

ID Token não é Access Token

O ID Token é destinado ao cliente e descreve autenticação. Não o use para chamar APIs. O Access Token possui audience e regras próprias.

Subject estável

Identifique o usuário pelo par iss + sub. E-mail pode mudar e não é necessariamente verificado ou único.

const externalIdentity = `${claims.iss}|${claims.sub}`;

Claims

Trate claims como dados do provedor. Verifique email_verified antes de usar e-mail em fluxos sensíveis. Não conceda permissões administrativas apenas por domínio de e-mail sem política adicional.

UserInfo

Quando necessário, chame o endpoint com Access Token:

const userInfo = await fetch(metadata.userinfo_endpoint, {
  headers: { authorization: `Bearer ${accessToken}` },
  signal: AbortSignal.timeout(3000)
});

Confirme que o sub retornado corresponde ao ID Token.

Sessão da aplicação

Depois de validar a identidade, crie uma sessão própria com cookie:

Set-Cookie: __Host-session=...; Path=/; Secure; HttpOnly; SameSite=Lax

Não armazene tokens grandes diretamente em cookie sem avaliar tamanho e exposição. Um identificador opaco de sessão costuma ser mais simples.

Refresh Tokens

Solicite offline_access somente quando necessário. Armazene refresh token criptografado, faça rotação e revogue em logout ou suspeita de comprometimento.

Consulte Refresh Tokens no Node.js.

Logout

Logout local remove a sessão da aplicação. Logout no provedor pode usar end_session_endpoint, quando suportado. Valide o redirecionamento pós-logout.

Prompt e max_age

prompt=login força nova autenticação. max_age limita idade da sessão no provedor. Use para operações sensíveis que exigem reautenticação.

ACR e AMR

acr pode representar nível de garantia e amr métodos usados, como senha e MFA. Só confie nesses valores se houver contrato claro com o provedor.

Multiple issuers

Em SaaS com vários provedores, selecione issuer a partir de configuração confiável do tenant, não diretamente de URL enviada pelo usuário. Faça discovery apenas em allowlist para evitar SSRF.

Mix-up attacks

Vincule a transação ao issuer e valide o issuer da resposta. Não reutilize o mesmo callback sem saber qual provedor iniciou o fluxo.

Clock skew

Permita pequena tolerância de relógio, mantendo servidores sincronizados. Tolerância grande enfraquece expiração.

Observabilidade

Registre:

  • issuer técnico;
  • resultado do fluxo;
  • erro público categorizado;
  • duração de discovery e token exchange;
  • falhas de state e nonce;
  • algoritmo e kid;
  • renovações e logouts.

Nunca registre tokens, códigos ou secrets.

Testes

  • state incorreto;
  • nonce incorreto;
  • issuer e audience inválidos;
  • token expirado;
  • kid desconhecido e rotação;
  • código reutilizado;
  • redirect URI inválida;
  • UserInfo com sub divergente;
  • sessão e logout;
  • provedor indisponível.

Erros comuns

  • confundir OAuth com autenticação;
  • não validar nonce;
  • identificar usuário por e-mail;
  • usar ID Token como Access Token;
  • discovery em URL arbitrária;
  • armazenar refresh token sem proteção;
  • aceitar redirect dinâmico;
  • registrar tokens;
  • não fixar algoritmos.

Conclusão

OpenID Connect no Node.js fornece autenticação federada sobre OAuth 2.0. O fluxo seguro depende de PKCE, state, nonce e validação completa do ID Token.

Use iss e sub como identidade, crie sessão própria e proteja refresh tokens. Trate discovery e múltiplos provedores como entradas controladas para evitar SSRF e confusão de issuer.

Consulte a especificação OpenID Connect Core e o documento de Discovery.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita