# Checklist de integração

> O que um sistema precisa fazer, e o que é recomendado, para usar a Central de Identidade como
> login sem quebrar quando as pessoas mudam de email, de empresa ou saem.

Esta página complementa [Para quem desenvolve](/docs/developers.md), que explica o protocolo
(endpoints, tokens, claims). Aqui está o que fazer com ele. Cada item é:

- **Obrigatório**: sem ele, a integração quebra ou abre uma falha de segurança.
- **Recomendado**: a integração funciona sem ele, mas pior para quem usa ou para quem mantém.

## Conexão

### Conecte por OIDC ou por OAuth2

**Os dois servem.** Use o que a biblioteca ou o framework do seu sistema oferecer:

- **OIDC**: o login devolve um **ID token** com quem é a pessoa. O sistema valida o token e lê
  as claims dele.
- **OAuth2**: o login devolve só o **access token**, e o sistema pergunta quem é a pessoa em
  `/userinfo`.

Nos dois casos o fluxo é o mesmo (authorization code com PKCE S256) e a pessoa é identificada
pelo `sub`. Com OAuth2:

- **Inclua o scope `openid`** junto com os outros que pedir. Sem ele, `/userinfo` recusa o
  token.
  Pedido sem `scope` (ou com `scope=` vazio) é tratado como `scope=openid`: o sistema recebe só o
  `sub`, não todos os scopes do cadastro.
- **Não leia o access token para saber quem é a pessoa**: ele é para a central, não para o seu
  sistema. A identidade vem de `/userinfo`.

## Identidade

### Identifique a pessoa pelo `sub`

**Obrigatório.**

O `sub` (o id da pessoa na central, como `vlidc_usr_…`) é **único e universal**: identifica a
mesma pessoa em todos os sistemas ligados à central, e nunca muda. É o mesmo id que a API usa.

Guarde o `sub` no usuário do seu sistema e use **só ele** para encontrar a pessoa a cada login.
**Nunca use email para isso**, nem o principal nem os confirmados: a pessoa troca de email, um
administrador corrige, e o mesmo endereço pode passar de uma pessoa para outra com o tempo.

### Associe os usuários que já existiam

**Obrigatório**, se o seu sistema já tinha usuários antes da integração.

Um usuário antigo ainda não tem `sub`, e pode estar cadastrado com um email diferente do email
principal dele na central. Para encontrá-lo:

1. Peça o scope `verified_emails`. A claim `verified_emails` traz **todos** os emails confirmados
   da pessoa, inclusive o principal. **Use sempre essa lista**, e não a claim `email`.
2. No login, procure primeiro pelo `sub`. Achou: é essa pessoa.
3. Não achou: procure, **só entre os usuários sem `sub`**, os que têm algum email da lista
   `verified_emails`.
   - **Achou exatamente um**: grave o `sub` nele. A partir daí, ele é encontrado pelo `sub`.
   - **Achou mais de um**: **não associe automaticamente**. Escolher um em silêncio junta duas
     pessoas numa só. Recuse o login ou marque o caso para alguém resolver na mão.
   - **Não achou nenhum**: é uma pessoa nova (veja [Não peça cadastro](#não-peça-cadastro)).

**Depois que um usuário tem `sub`, o email nunca mais entra na busca dele.**

A associação também pode ser feita de uma vez, antes de qualquer login, pela API: pergunte à
central quem é dono de cada email do seu sistema (`QUERY /api/v1/users/email-owners`, ou o filtro
`ownsEmail` em `GET /api/v1/users`). Só conta o dono de um email principal ou confirmado, seguindo
as mesmas regras acima. Detalhes em [Para quem desenvolve](/docs/developers.md#achar-uma-pessoa-pelo-email).

## Cadastro e dados

### Não peça cadastro

**Recomendado.**

No primeiro login, crie o usuário do seu sistema com os dados que vêm da central (nome, email,
foto). A pessoa não deveria preencher um formulário com o que a central já sabe.

### Use os dados da central

**Recomendado.**

Nome, email, foto e vínculo profissional **vêm da central**. Atualize a sua cópia a cada login
(pelo ID token ou por `/userinfo`) e **não deixe a pessoa editar esses dados no seu sistema**:
as duas versões se desencontram, e a da central é a que os outros sistemas veem. Para corrigir
algo, a pessoa fala com um administrador da central.

### Não exija email único

**Recomendado.**

Um email pode mudar de dono: alguém sai da empresa e, anos depois, o mesmo endereço é dado a
outra pessoa. Na central, as duas são pessoas diferentes, com `sub`s diferentes. Se o seu sistema
exige email obrigatório e único, a segunda pessoa não consegue ser cadastrada.

**Afrouxe essa regra**: deixe o email opcional, ou sem unicidade. E se aparecer uma pessoa nova
(um `sub` que você não conhece) com um email que já está num usuário do seu sistema, **apague o
email do usuário antigo**: o endereço provavelmente mudou de dono. É raro, mas acontece. Isso só
acontece com usuários que já têm `sub`: um usuário sem `sub` com esse email teria sido associado
à pessoa no passo de [associação](#associe-os-usuários-que-já-existiam).

### Não presuma que um campo vem preenchido

**Obrigatório.**

- `employer` é `null` para freelancers.
- `picture` e `slack` podem vir `null`.
- `served_organizations` e `verified_emails` podem vir vazios.
- Com o scope `access`, `groups` vem `{}` e `permissions` vem `[]` para quem não tem nenhum.

### Peça só os scopes que usa

**Recomendado.**

Cada scope libera mais dados da pessoa. Peça os de que o sistema precisa de verdade.

## Acesso e segurança

### Mantenha as permissões no seu sistema

**Obrigatório.**

A central diz **quem** é a pessoa; **o que ela pode fazer** no seu sistema é decisão do seu
sistema. Se ele precisa de grupos ou permissões vindos da central, peça o scope `access` (claims
`groups` e `permissions`, em [Para quem desenvolve](/docs/developers.md#quem-é-a-pessoa-scopes-e-claims))
e guarde no seu sistema o que cada grupo ou permissão significa, **pelo slug**, nunca pelo nome.
As permissões vêm todas, de todos os sistemas: ignore as que você não conhece. Os papéis da
central (administrador de pessoas, global etc.) servem só para administrar a própria central e
não aparecem nas claims.

### Desligue o login próprio do sistema

**Recomendado.**

Uma senha local é uma porta paralela: quando um administrador desativa alguém na central, essa
porta continua aberta. Depois da integração, a central deve ser o único jeito de entrar. Se
precisar de uma conta de emergência, mantenha uma só, documentada.

### Reaja à desativação

**Obrigatório.**

Quando alguém é desativado, a central revoga os tokens da pessoa, mas o seu sistema só fica
sabendo se perguntar. **Não mantenha uma sessão local por muito mais que 1 hora** (a validade do
access token) sem renovar o token. Se o refresh for recusado, encerre a sessão local.

### Ofereça a saída pela central

**Recomendado.**

Sair do seu sistema não tira a pessoa da central, e ela continua entrando direto nos outros
sistemas. Ofereça a saída por `/end-session` (veja [Para quem desenvolve](/docs/developers.md)),
pelo menos como opção.

### Valide os tokens com uma biblioteca

**Obrigatório.**

Use uma biblioteca cliente de OIDC ou de OAuth2 da sua linguagem para o fluxo. Com OIDC, é ela
que valida o ID token (assinatura, `iss`, `aud`, validade e `nonce`). **Não escreva o fluxo nem
a validação à mão**: os erros sutis aqui viram falha de segurança.

### Valide o token de outro sistema

**Obrigatório**, se a API do seu sistema recebe chamadas de outros sistemas da empresa.

Confira assinatura, `exp`, `nbf`, se o `iss` é o `issuer` da central, se o `aud` contém o seu
client id e se o `client_id` é de um sistema que você aceita (e diferente do seu: um token que
você mesmo pediu não é chamada de outro sistema). O passo a passo está em [Para quem desenvolve](/docs/developers.md).

## Webhooks

Só se o seu sistema quer ser avisado quando algo muda na central. O formato e o passo a passo
estão em [Para quem desenvolve](/docs/developers.md#receber-webhooks).

### Verifique cada aviso antes de confiar

**Obrigatório.**

Quem conhece a URL pode mandar um `POST` falso. Valide a assinatura do JWT com o JWKS da central
(com uma biblioteca JOSE, como no login) e confira `iss`, `aud` (o seu client id) e o `typ`
`secevent+jwt`. Rejeite com 4xx o que não passar.

### Responda rápido e deduplique pelo `jti`

**Obrigatório.**

Responda 2xx assim que guardar o aviso, em poucos segundos (o limite da central é 5s), e
processe depois. Falha ou demora faz a central repetir o **mesmo** aviso, então o mesmo `jti`
pode chegar mais de uma vez: guarde os já tratados e ignore os repetidos. Os avisos chegam em
ordem, mas pense neles como "algo mudou ali": busque o estado atual na API em vez de confiar
no aviso como cópia dos dados.

### Acompanhe o estado do webhook

**Recomendado.**

Um webhook falhando por cerca de 24h é pausado, e os avisos esperam na fila. Peça a um
administrador global para retomar depois de consertar o receptor. Nada se perde: a entrega
continua de onde parou. Use o "evento de verificação" para testar o receptor ao ligá-lo.

## Na página inicial da central

### Faça a URL do app já iniciar o login

**Recomendado.**

A página inicial da central lista os sistemas da empresa. Quem clica num deles já está logado
na central, então a URL cadastrada para o app deveria **levar direto ao login pela central**,
não a uma tela de "entrar" do seu sistema. Combine essa URL com o administrador de diretório
que cadastra o app.
