Skip to main content
O Quick Start cobre o caminho feliz em 5 passos. Este guia é a versão profunda: três padrões de implementação (SPA, backend tradicional, mobile nativo), o fluxo OAuth2 + PKCE etapa por etapa, validação de id_token via JWKS, respostas ilustrativas de cada endpoint, comportamento esperado em erros e o que fazer com o token quando ele expira.
Prefere aprender por exemplo? O repo cativa-sso tem apps de referência prontos pra rodar. A pasta login-com-cativa (Node + Express) implementa todos os passos deste guia, ponta a ponta.

Cenário

Sua empresa tem um app, pode ser uma SPA React em outro domínio, um portal Rails com sessões server-side, ou um app iOS/Android nativo. Sua comunidade já vive numa Cativa e você quer que o usuário entre nesse app com a mesma conta que ele usa na comunidade, sem criar credencial separada. A Cativa expõe um IdP OIDC standard por tenant. Qualquer biblioteca OIDC client (oidc-client-ts, auth0/spa-js, next-auth, passport-openidconnect, AppAuth-iOS, AppAuth-Android) consegue falar com ele a partir do discovery URL do tenant.

Pré-requisitos

  1. Um OAuth App registrado no Console: vá em app.cativa.digital/admin/developers, aba OAuth Apps, clique Criar app. Anote o client_id (YOUR_CLIENT_ID) e o client_secret (YOUR_SECRET), o secret aparece uma única vez.
  2. Um redirect URI registrado no mesmo app. Pode adicionar múltiplos (ex: produção + staging + localhost).
  3. O customerName (slug do tenant): confirme com o admin da comunidade. É o subdomínio público da Cativa daquele tenant.
Os endpoints SSO da Cativa seguem OIDC e são organizados por tenant: https://apis.cativalab.digital/tenant/api/v2/sso/{customerName}/.... O documento de descoberta fica em https://apis.cativalab.digital/tenant/api/v2/sso/{customerName}/.well-known/openid-configuration e lista todos os endpoints e algoritmos suportados (S256 para PKCE, ES256 para id_token).

O fluxo em uma imagem

O documento de descoberta é a fonte de verdade dos endpoints. Um GET no .well-known/openid-configuration do tenant devolve algo assim (resposta ilustrativa; o schema completo fica na API Reference):

Decida qual fluxo usar

Quando usar: seu app é um frontend estático (React/Vue/Svelte) servido por CDN, sem backend confiável pra guardar client_secret. PKCE (Proof Key for Code Exchange) substitui o segredo do client por um par verifier/challenge gerado a cada login.
1

Gere code_verifier e code_challenge

O code_verifier é uma string aleatória que fica no navegador. O code_challenge é o SHA-256 do verifier, base64url-encoded, esse vai pro /authorize.
2

Redirecione para o /authorize

Guarde o verifier e o state antes de sair da página (você vai precisar deles no callback).
3

Troque o code por tokens

A Cativa redireciona o usuário pra https://meuapp.com/callback?code=...&state=.... Valide o state e troque o code por tokens.Como SPA não pode guardar client_secret, o /token aceita PKCE como prova: você manda o code_verifier original (não o challenge) e a Cativa recomputa o SHA-256 e compara com o code_challenge que ela guardou da etapa anterior.
O /token responde 200 OK com (resposta ilustrativa; schema completo na API Reference):
Mesmo em SPA, a Cativa exige client_secret no body do /token. Se você quer um fluxo realmente sem secret no frontend, monte um endpoint de proxy no seu backend que recebe o code da SPA e faz a troca server-side (cai no padrão Backend tradicional abaixo).
4

Pegue o perfil e faça login local

O /userinfo responde 200 OK com (resposta ilustrativa):
Não persista o access_token em localStorage, ele é vulnerável a XSS. Mantenha em memória (estado da SPA) ou em sessionStorage se aceitar perder a sessão entre abas.

Validar o id_token via JWKS

O id_token retornado pelo /token é um JWT assinado em ES256. Você deve validar a assinatura antes de confiar nas claims (sub, email, etc.), isso evita que um atacante substitua o token por um falsificado. A chave pública pra validar fica no JWKS do tenant:
A discovery doc aponta pra esse JWKS, bibliotecas OIDC client baixam e cacheiam a chave automaticamente.
Depois de validado, o payload do id_token tem esta forma (ilustrativa):

Sessão e renovação de token

O access_token retornado pelo SSO da Cativa é de curta duração (configurado no OAuth App, default 1h). Escolha a estratégia que se encaixa:
  1. Renovar com refresh_token (recomendado): toda troca de authorization_code já devolve um refresh_token (opaco). Troque-o por um access_token novo quando o atual expirar:
    A resposta (ilustrativa) traz um access_token novo e um refresh_token novo, os tokens são rotacionados, então guarde o refresh novo e descarte o antigo (ele é invalidado no uso):
  2. Re-login silencioso quando expira: quando expires_in chegar a 0, redirecione o usuário pro /authorize de novo. Se ele ainda tem sessão na Cativa, o IdP devolve um novo code sem pedir senha de novo (single sign-on).
  3. Trate o token como sessão atrelada ao seu app: guarde apenas a identidade (sub, email) na sua sessão e gere o seu próprio JWT/cookie. O access_token da Cativa é usado só no momento do login.

Logout

Hoje não há um endpoint OIDC end_session dedicado pra apps OAuth externos. O fluxo recomendado é:
  1. No seu lado: descarte a sessão local (apague cookie/session/Keychain), redirecione o usuário pra um destino “deslogado”.
  2. Opcional, se quiser deslogar também da comunidade Cativa: redirecione o usuário pra https://{customerName}.cativa.digital/logout (substituindo {customerName} pelo subdomínio do tenant).
Endpoint OIDC standard end_session para parceiros externos está em desenvolvimento. Quando disponível, esta página será atualizada com cURL e exemplo de redirect com post_logout_redirect_uri.

Erros comuns

A redirect_uri enviada pra /authorize (e re-confirmada no /token) precisa ser idêntica a uma das URIs cadastradas no OAuth App do Console. Compare com cuidado: trailing slash, http vs https, e maiúsculas/minúsculas em paths importam. A resposta de erro tem a forma:
O code retornado pelo /authorize tem TTL curto (alguns minutos). Se sua troca demora, porque o backend redireciona pra outra rota antes, ou porque você está depurando manualmente, o code expira. Sempre faça a troca imediatamente no callback.
O code é single-use. Se seu callback é chamado duas vezes (ex: usuário deu reload na tela de callback), a segunda troca falha com esse erro. Isso é esperado, apenas redirecione pra home da SPA quando você já tiver os tokens em sessão.
Verifique:
  • Você não confundiu client_id e client_secret.
  • O secret não foi rotacionado no Console (gerar novo invalida o anterior).
  • Não tem espaço/quebra de linha extra na variável de ambiente (acontece com cat .env quando o arquivo veio de Windows).
O code_verifier enviado no /token não bate com o code_challenge enviado no /authorize. Causas comuns: você gerou um novo verifier antes do callback (perdeu o original), está fazendo SHA-256 sobre bytes diferentes (UTF-8 vs ASCII), ou está aplicando base64 padrão em vez de base64url.
O access_token expirou ou está com formato errado. Cheque o Authorization: Bearer <access_token> (não use o id_token aqui, /userinfo valida o access_token). Se o token está válido mas você ainda recebe 401, valide o iss do access_token (deve ser https://apis.cativalab.digital/tenant/api/v2/sso/{customerName}).
Confirme:
  • algorithms: ['ES256'] (a Cativa assina com ES256, não RS256).
  • issuer exatamente https://apis.cativalab.digital/tenant/api/v2/sso/{customerName} (sem trailing slash).
  • audience é o seu client_id.
  • Sua biblioteca está buscando o JWKS do issuer correto (e cacheando, pra não bater no endpoint a cada login).

Próximos passos

Badges como permissão

Como o sub do id_token aparece na comunidade e como badges controlam o que esse usuário pode acessar.

Login federado (IdP da empresa)

O fluxo inverso: a Cativa como Relying Party, autenticando membros pelo IdP da própria empresa.

Quick Start: API Key

Para chamadas server-to-server (sem usuário interativo), use uma API Key em vez de OAuth.

App de exemplo (GitHub)

Implementações de referência prontas pra rodar (Node + Express). A pasta login-com-cativa implementa exatamente este fluxo: discovery, PKCE, troca de token e validação via JWKS.