Para quem desenvolve
Como ligar um sistema à Central de Identidade para login (OpenID Connect) e como usar a API da central para gerir pessoas.
A Central de Identidade é um provedor OpenID Connect (OIDC): o padrão aberto de login que fica por cima do OAuth2. Em vez de guardar senhas, o seu sistema manda a pessoa para a central, ela entra lá, e o sistema recebe de volta quem ela é. Qualquer biblioteca cliente de OIDC da sua linguagem serve; esta página diz o que a central espera e onde ela foge do comum.
Antes de integrar, leia também o Checklist de integração: o que o seu sistema precisa fazer, além do protocolo.
Antes de começar: o client
Para a central aceitar o seu sistema, ele precisa de um client: o cadastro do sistema na
central, com um identificador (client_id). Quem cadastra é um administrador global. Leve para
ele:
- Tipo: confidencial, se o sistema guarda um segredo no servidor (o caso comum de um backend), ou público, se não tem onde guardar (um app que roda só no navegador ou no celular). Essa escolha não muda depois.
- Redirect URIs: os endereços para onde a central devolve a pessoa depois do login.
- Post-logout redirect URIs, se o sistema for usar a saída pela central (veja Sair).
- Scopes de que o sistema precisa (veja Quem é a pessoa).
- Grants:
authorization_codeerefresh_tokenpara login;client_credentialssó se o sistema for chamar a API em nome próprio (veja API).
Um client confidencial recebe um secret, a senha do sistema. Ele aparece uma vez só, para o administrador, no momento do cadastro: guarde na hora, num cofre de segredos.
Login
Endpoints do login
| O quê | Caminho |
|---|---|
| Discovery | GET /.well-known/openid-configuration |
| Autorização | GET /authorize |
| Token | POST /token |
| UserInfo | GET ou POST /userinfo |
| Chaves públicas (JWKS) | GET /jwks |
| Saída | GET /end-session |
O documento de discovery tem esses endereços e o issuer, mas não lista os scopes e claims:
eles estão na seção Quem é a pessoa, abaixo.
O fluxo
A central só aceita o fluxo authorization code com PKCE, e o PKCE é obrigatório para todo
client, inclusive os confidenciais. PKCE é a prova de que quem troca o código pelo token é o
mesmo sistema que pediu o login: o sistema gera um segredo aleatório (code_verifier), manda o
hash dele no pedido de login (code_challenge) e o segredo original na troca.
-
O sistema manda a pessoa para
/authorize:https://home.vetorzero.com.br/authorize ?response_type=code &client_id=meu-sistema &redirect_uri=https://meu-sistema.exemplo.com.br/callback &scope=openid profile email &state=<aleatório> &nonce=<aleatório> &code_challenge=<BASE64URL(SHA256(code_verifier))> &code_challenge_method=S256Mande
code_challenge_method=S256sempre. Sem ele, a biblioteca do servidor assumeplain, que a central recusa. -
A pessoa entra com a conta Google (ou passa direto, se já tiver entrado) e volta para a
redirect_uricomcodeestate. Não existe tela de consentimento: todos os sistemas ligados à central são da própria empresa. -
O sistema troca o código por tokens:
curl -X POST "https://home.vetorzero.com.br/token" \ -u 'meu-sistema:SECRET' \ -d grant_type=authorization_code \ -d code=CODE \ -d redirect_uri=https://meu-sistema.exemplo.com.br/callback \ -d code_verifier=CODE_VERIFIERUm client confidencial se autentica com HTTP Basic (como acima) ou com
client_ideclient_secretno corpo. Um client público manda só oclient_idno corpo. -
A resposta traz
access_token,id_tokenerefresh_token. Oid_tokenjá tem as claims dos scopes pedidos; confira nele ononceque você mandou.
Tokens
| Token | Validade |
|---|---|
| Código de autorização | 10 minutos |
| Access token | 1 hora |
| ID token | 1 hora |
| Refresh token | 1 mês |
- O access token e o ID token são JWT assinados com RS256. As chaves públicas estão em
/jwks. - Cada refresh token vale uma vez só: ao usá-lo, você recebe um novo e o antigo é revogado. Guarde sempre o último.
- A central não tem endpoint de revogação nem de introspecção de token.
Regras de redirect URI
- Tem que ser
https. A exceção éhttpemlocalhostou127.0.0.1, para desenvolvimento. - A comparação é exata, caractere por caractere. Em
http://127.0.0.1a porta é ignorada; emhttp://localhost, a porta precisa bater.
Quem é a pessoa: scopes e claims
Cada scope libera um conjunto de claims (os dados da pessoa). O scope openid entra sempre.
| Scope | Claim | Tipo | O que é |
|---|---|---|---|
openid |
sub |
string | Identificador da pessoa, como vlidc_usr_… |
profile |
name |
string | Nome |
profile |
picture |
string ou null | Foto da conta Google principal |
email |
email |
string | Email principal |
email |
email_verified |
bool | Se o email principal foi confirmado |
verified_emails |
verified_emails |
string[] | Todos os emails confirmados |
employment |
employer |
string ou null | Domínio da empresa que contratou a pessoa; null para freelancer |
employment |
served_organizations |
string[] | Domínios das empresas que ela atende |
employment |
job_title |
string ou null | Cargo |
employment |
department |
string ou null | Departamento |
As claims vêm no ID token e também em /userinfo.
Identifique a pessoa pelo sub, nunca pelo email. Isso e o resto do que o seu sistema
precisa fazer com essas claims, incluindo como associar usuários que já existiam, estão no
Checklist de integração.
/userinfo
/userinfo devolve as mesmas claims a partir de um access token. O token vai só no header
Authorization: Bearer <token>, tanto em GET quanto em POST; não há parâmetro no corpo.
curl "https://home.vetorzero.com.br/userinfo" -H "Authorization: Bearer ACCESS_TOKEN"
Um token de client_credentials é recusado aqui (403): ele não representa uma pessoa.
Sair
Sair da central não tira a pessoa do seu sistema, e sair do seu sistema não tira ela da central. Cada lado tem a sua sessão.
Para encerrar também a sessão na central, mande a pessoa para /end-session, com os parâmetros
na query string:
https://home.vetorzero.com.br/end-session
?id_token_hint=<o id_token da pessoa>
&post_logout_redirect_uri=https://meu-sistema.exemplo.com.br/
&state=<opcional>
- A
post_logout_redirect_uriprecisa estar cadastrada no client. Ela também exigeid_token_hintouclient_id. - Com
id_token_hintválido, a saída é direta. Sem ele, a central pode mostrar uma tela de confirmação antes.
Pessoas desativadas
Quando um administrador desativa alguém, a central revoga os tokens dessa pessoa: /userinfo e
o refresh passam a recusar. Um JWT que o seu sistema valida sozinho, só com a chave pública,
continua válido até expirar (no máximo 1 hora). Se o seu sistema precisa reagir na hora,
consulte /userinfo ou faça refresh em vez de confiar só na validade do JWT.
API
A API em /api/v1 permite que outro sistema gerencie pessoas: listar, consultar, cadastrar,
editar, desativar e cuidar de emails. A especificação completa, em OpenAPI, está em /api/doc
(para ler no navegador) e em /api/doc.json.
Acesso
Toda chamada leva um access token no header Authorization: Bearer. Há dois jeitos de obter um:
-
Em nome do próprio sistema (
client_credentials): o sistema age como ele mesmo, com os papéis que o client recebeu. Exige client confidencial.curl -X POST "https://home.vetorzero.com.br/token" -u 'meu-sistema:SECRET' -d grant_type=client_credentials -
Em nome de uma pessoa: o access token do login dela. A chamada vale com os papéis da pessoa.
Nos dois casos, o client precisa ter "Acesso à API" liberado por um administrador global, que também define os IPs de onde ele pode chamar (sem nenhum IP, qualquer um é aceito). Todos os endpoints de hoje exigem o papel de administrador de pessoas. As chamadas ficam registradas na auditoria da central, com o client de origem.
O bearer é o access token, não o secret. Mandar o secret no lugar dá 401.
Endpoints da API
| Método | Caminho | O quê |
|---|---|---|
GET |
/api/v1/users?limit=&offset= |
Lista pessoas |
POST |
/api/v1/users |
Cadastra uma pessoa (name, email) |
GET |
/api/v1/users/{id} |
Consulta uma pessoa |
PUT |
/api/v1/users/{id}/profile |
Troca nome e email |
PUT |
/api/v1/users/{id}/employment |
Troca empregador, empresas atendidas, cargo e departamento |
POST |
/api/v1/users/{id}/emails |
Adiciona um email (a pessoa confirma pelo link) |
DELETE |
/api/v1/users/{id}/emails/{address} |
Remove um email |
POST |
/api/v1/users/{id}/deactivate |
Desativa |
POST |
/api/v1/users/{id}/reactivate |
Reativa |
O {id} é o mesmo sub do login. Empresas são identificadas pelo domínio. Uma pessoa
cadastrada pela API recebe o convite por email, como no cadastro pela tela, e não há exclusão de
pessoa: o equivalente é desativar.
Convenções
- Os nomes da API estão em inglês (campos, mensagens de erro).
- Não há
PATCH. OPUTmanda o estado inteiro do recurso: toda chave é obrigatória, inclusive as que aceitamnull. Chave faltando dá erro. Idempotency-Key(opcional, só emPOST): repetir a mesma chamada com a mesma chave devolve a resposta guardada, com o headerIdempotent-Replayed: true, em vez de repetir o efeito. Só respostas 2xx são guardadas, por pelo menos 7 dias. A mesma chave com outro corpo dá 422; uma chamada enquanto a primeira ainda roda dá 409.- Paginação:
limitde 1 a 100 (padrão 50) eoffset. A resposta trazitems,totale os linksnexteprev. - Erros seguem o RFC 9457 (
application/problem+json), comtitle,statuse, quando ajuda,detail. Erro de validação é 422, com a lista emviolations; recurso inexistente é 404; conflito (como email já usado) é 409.
Quando algo dá errado
invalid_request "PKCE is required" no /authorize: faltou o code_challenge. Se ele foi,
confira o code_challenge_method=S256.
invalid_client no /token: secret errado, client desativado ou, no client_credentials,
chamada de um IP fora da lista do client.
Erro no /authorize logo de cara, sem passar pelo login: a redirect_uri provavelmente não bate
exatamente com a cadastrada. Atenção à barra no
fim e à porta do localhost.
access_denied no /authorize durante um teste: o administrador está impersonando outra
pessoa na central. Impersonando, a central não deixa entrar em nenhum sistema.
403 em /userinfo: o token é de client_credentials, que não representa uma pessoa.
401 na API: falta o bearer, o bearer é o secret em vez do access token, ou o client está
desativado, sem acesso à API ou chamando de um IP não liberado. O detail diz qual.