Identidade na web OpenID Connect · SSO · Keycloak
Artigo interativo

Você não tem quarenta contas. Tem uma identidade.

SSO é a experiência de entrar uma vez e circular por vários apps. OpenID Connect é o protocolo que tornou isso um padrão na web — o mecanismo por trás de “Entrar com Google”, Okta, Auth0, Microsoft e quase todo botão de login moderno.

Leitura · ~10 min Interativo · fluxo + playground Sem backend · tudo neste arquivo

O problema não é a senha. É a quantidade.

Cada app que você usa — e-mail, CI, Figma, o RH da empresa — precisa saber quem você é. A solução ingênua é cada um ter a sua tabela de usuários. Você vira um zelador de senhas. A empresa vira um zelador de vazamentos.

SSO inverte o desenho: um provedor guarda a identidade. Os apps só pedem emprestado um atestado de que você é você. A senha (ou a passkey, ou o MFA) vive num lugar só.

SSO é a experiência. OpenID é o contrato.

Single Sign-On não é um protocolo. É o resultado: autenticar uma vez num provedor e entrar em vários serviços sem digitar de novo. Pode ser feito com cookies de domínio compartilhado (o jeito antigo da intranet), com SAML (o jeito clássico da empresa) ou com OpenID Connect (o jeito da web moderna).

OpenID Connect — OIDC — é uma camada de identidade em cima do OAuth 2.0. OAuth sozinho responde “este app pode gastar o seu crédito / ler o seu calendário?”. OIDC responde “quem está do outro lado?”. Os dois viajam juntos: o mesmo redirecionamento, o mesmo code, tokens diferentes.

Regra de ouro. OAuth 2.0 autoriza. OpenID Connect autentica. SSO é o que o usuário sente quando o provedor já tem uma sessão viva e o segundo app entra sem senha.

Três papéis. Sempre.

Todo fluxo OIDC é um triângulo. Se você memorizar só isso, o resto se encaixa.

👤

Você

End user · resource owner

Dono da identidade. Autentica no provedor, não no app. O browser é o seu emissário — é ele que carrega os redirects.

O app

Relying Party · client

Confia no provedor. Nunca vê a sua senha. Recebe um id_token e, se pediu, um access token para APIs.

O provedor

OpenID Provider · IdP

Google, Okta, Auth0, Entra ID, Keycloak. Autentica, guarda a sessão, assina o JWT, emite o code.

O app se cadastra no provedor e ganha um client_id (público) e, se for um backend, um client_secret. Também registra a redirect_uri — o único endereço para o qual o provedor devolve o usuário. Sem isso, um site malicioso redirecionaria o code para si.

O fluxo, no pulso.

O caminho padrão hoje é o Authorization Code Flow (com PKCE se o app for público, tipo SPA ou mobile). Clique os passos. O palco mostra quem está falando com quem — e o que atravessa o browser versus o que vai nos bastidores.

Você · browser
App · relying party
Provedor · OP / IdP

O ID Token é um JWT. Três pedaços, uma assinatura.

Depois do code, o app recebe um id_token: um JSON Web Token. Base64url, três partes separadas por ponto. Clique em cada uma.

headereyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0xIn0
payloadeyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwic3ViIjoiYWx0YW1pciIsImF1ZCI6ImFwcC1jbGllbnQiLCJleHAiOjE3NTYyNjU2MDAsImlhdCI6MTc1NjI2MjAwMCwibm9uY2UiOiJuLTQyIiwibmFtZSI6IkFsdGFtaXIiLCJlbWFpbCI6ImFsdGFtaXJAZXhhbXBsZS5jb20ifQ
signaturedBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

O app não confia no token só porque ele chegou. Valida: assinatura (chave pública JWKS do provedor), iss bate com o provedor, aud é o próprio client_id, exp no futuro, nonce é o mesmo que o app gerou. Só então cria a sessão local — um cookie do app, independente do cookie do IdP.

A mágica do segundo app.

SSO não é o app A avisando o app B. Os dois nem se conhecem. O truque é o cookie de sessão no domínio do provedor. O primeiro login acende essa sessão. O segundo app só redireciona de novo para o mesmo IdP — e o IdP, vendo o cookie, pula a senha e devolve outro code.

Entre nos três apps abaixo. A primeira vez pede credencial. As seguintes, não.

Provedor · idp.example

sem sessão
cookie: —
pronto. escolha um app e entre.

Onde as pessoas se perdem.

Três confusões que aparecem em toda code review de auth.

OAuth 2.0

  • Autorização: o que um client pode fazer em nome do usuário.
  • Token típico: access_token (muitas vezes opaco).
  • Escopos: calendar.read, repo.
  • O resource server (a API) consome o access token.

OpenID Connect

  • Autenticação: quem é o usuário, atestado pelo provedor.
  • Token típico: id_token (sempre JWT).
  • Escopo obrigatório: openid. Extra: profile, email.
  • O client (o app) consome o ID token. Não manda o ID token para APIs.

o mesmo redirect, intenções diferentes

Front-channel vs back-channel

Redirects pelo browser são o front-channel: visíveis na barra de URL, sujeitos a leak no histórico, em logs, em referrers. Por isso o code é de uso único e vive segundos. A troca code → tokens acontece no back-channel, servidor a servidor, onde o secret (ou o PKCE verifier) não aparece no browser.

PKCE

SPAs e apps nativos não conseguem esconder um client_secret. PKCE (Proof Key for Code Exchange) faz o app gerar um code_verifier aleatório, mandar o hash (code_challenge) no authorize, e apresentar o verifier só na troca do code. Um atacante que roube o code na URL não consegue o token.

Logout não é um só botão

Sair do app apaga a sessão local. A sessão do IdP continua — e é isso que faz o SSO funcionar no próximo app. Logout único (RP-initiated logout) é um pedido extra ao provedor para matar a sessão central. Sem ele, “sair” num app não te tira dos outros.

Quando o IdP quebra, todos os apps caem com ele.

SSO concentra a confiança num só lugar. Keycloak é um OpenID Provider open source (e o motor do Red Hat Build of Keycloak). Em agosto de 2026 saiu a CVE-2026-18963: um atacante sem login conseguia trocar a senha de qualquer usuário — inclusive admin — e herdar o SSO inteiro.

CVE-2026-18963 CVSS 9.1 · Critical CWE-640 · reset fraco sem autenticação MFA do login não cobre

O reset como deveria ser

Esqueci minha senha não pode ser “digitei o username, agora escolho outra”. A prova de posse é o e-mail cadastrado. O IdP manda um action token assinado na mensagem. Só quem abre aquele link — ou seja, quem controla a caixa — pode chegar na tela de senha nova.

Isso é o equivalente, no provedor, do nonce no ID token: um passo que precisa ter acontecido de verdade, não só “a sessão acha que aconteceu”.

O que quebrou

O fluxo reset-credentials não validava direito o estado entre os passos. Duas peças se combinaram, a partir do Keycloak 26.0.0:

Estado da tela solto

O fluxo guardava “já mostrei o seletor de autenticador” como uma flag genérica, sem amarrar ao passo que a ligou. Dava para revisitar o fluxo num ponto posterior, como se aquele passo já tivesse sido cumprido.

E-mail sem o token

O autenticador que deveria exigir o action token do e-mail aceitava sucesso mesmo sem essa prova. O fluxo seguia para “definir senha nova”.

CWE-640: recuperação de senha que não prova a identidade

Quem conhecia o username ou o e-mail da vítima iniciava o reset e chegava a gravar credencial nova. Sem clicar no link, sem a caixa de e-mail, sem interação da vítima. O 2FA do login do browser não entra neste fluxo por desenho — reset de senha, no default, pula o OTP. Depois da senha nova, o atacante ainda podia tirar o MFA e ficar dono da conta.

Raio de explosão do SSO. Os apps relying party não viram nada de errado: o IdP emitiu code e id_token válidos para a identidade roubada. Um bug no provedor é um bug em todos os clientes OIDC daquele realm.

Como foi mitigado

O patch oficial é o PR #51844, reportado por James Paremain e publicado pela Red Hat em 18 de agosto de 2026. Duas correções, as duas necessárias:

Versões corrigidas. Linhas sem patch (26.0–26.3, 26.5) não vão receber correção — sai delas.

26.7
26.7.2
community
26.6
26.6.6
RHBK
26.4 LTS
26.4.15
RHBK
main
26.8.0
já inclui

Enquanto o patch não sobe: desligar “Forgot password” em todos os realms, inclusive o master. Console: Realm settings → Login → Forgot password → Off. Isso fecha o fluxo vulnerável; usuários perdem o self-service até o upgrade. Keycloak 25.x e anteriores não têm o bug — ele nasceu no 26.0.0.

Depois de patchar: procurar UPDATE_PASSWORD sem evidência de consumo do action token do e-mail na mesma sessão, e tratar contas privilegiadas como comprometidas se a exposição coincidiu com resets estranhos. Forçar senha nova e derrubar sessões de admin não é paranoia, é higiene.

Fontes: Red Hat CVE-2026-18963, keycloak#51833, notas 26.7.2. Sem receita de exploração aqui — só o mecanismo e o remendo.

Glossário rápido

OP / IdP
OpenID Provider, o servidor de identidade. Também chamado Identity Provider.
RP / client
Relying Party: o aplicativo que confia no OP.
scope=openid
O interruptor que transforma um OAuth num login OIDC e pede um ID token.
state
Valor aleatório anti-CSRF. O app verifica se o que voltou é o que ele mandou.
nonce
Valor aleatório amarrado ao ID token, contra replay.
code
Autorização de curta duração, um uso. Não é o login em si — é o ticket para os tokens.
id_token
JWT assinado dizendo quem autenticou, para quem, até quando.
access_token
Credencial para chamar APIs. Não use como prova de identidade do usuário no seu app.
prompt=none
Pedido silencioso: se houver sessão no IdP, devolve code; senão, erro. Base do SSO invisível.
SAML
O primo XML, ainda dominante em enterprise antigo. Mesma ideia de SSO, outro envelope.
action token
JWT curto que o Keycloak manda no e-mail de reset. É a prova de que quem está no fluxo controla a caixa.
CVE-2026-18963
Bypass no reset-credentials do Keycloak 26: dava para trocar a senha sem o e-mail. Patch em 26.7.2 / 26.6.6 / 26.4.15.