Fluxo de autorização
Cada redirect e requisição do fluxo de código de autorização, em ordem, com os parâmetros que seu projeto realmente aceita.
Um fluxo só, porque o OAuth 2.1 removeu os outros: código de autorização com
PKCE. Clientes públicos e confidenciais rodam a mesma sequência; a única
diferença é se um client_secret acompanha a requisição de token.
1. A requisição de autorização
GET /oauth/authorize
?client_id=…
&redirect_uri=https://acme.example.com/callback
&response_type=code
&scope=openid%20email
&state=…
&code_challenge=…
&code_challenge_method=S256
&nonce=…
&resource=…client_idobrigatórioOptionalA aplicação registrada.
redirect_uriobrigatórioOptionalPrecisa casar exatamente com um registrado para o cliente.
response_typeobrigatórioOptionalcode. Não existe outro no OAuth 2.1.
scopeopcionalOptionalSeparado por espaço. Omitido, cai em email.
staterecomendadoOptionalDevolvido intacto no redirect de volta. Sua defesa contra CSRF.
code_challengeobrigatórioOptionalBase64url do SHA-256 do seu verifier.
code_challenge_methodobrigatórioOptionalS256.
nonceopcionalOptionalEcoado no ID token. Amarra o token a esta requisição.
resourceopcionalOptionalA API para a qual o token se destina, quando seu projeto protege mais de uma.
Se o Servidor OAuth estiver desligado no ambiente, este endpoint responde 403
antes de qualquer outra coisa.
2. Para onde vão os erros
É a parte que as integrações erram, e a regra vem direto da spec: onde um erro aparece depende de o redirect URI já ter sido validado ou não.
Antes da validaçãoJSON, 400Optionalclient_id desconhecido, client_id ausente, redirect_uri que não casa. Não
dá para redirecionar — mandar erro para um URI não verificado entregaria a um
atacante um redirecionador funcional. Voltam como JSON.
Depois da validação302 para o redirect_uriOptionalEscopo não suportado, response_type inválido, consentimento negado. Esses
redirecionam de volta com ?error=…&error_description=…&state=…, porque já se
sabe que o cliente é dono daquele URI.
Então um cliente que só trata ?error= no callback vai perder silenciosamente a
primeira classe de falhas. Trate as duas.
3. A passagem para a sua tela de consentimento
Validada a requisição, seu projeto cria uma autorização — um registro efêmero do que foi pedido — e redireciona o navegador para:
{siteUrl}{authorizationPath}?authorization_id=…As duas metades vêm das configurações do seu projeto. O usuário agora está na sua aplicação, e a nulvless sai de cena até a sua página chamar de volta.
4. Lendo e respondendo
Sua tela de consentimento busca o que foi pedido:
GET /oauth/authorizations/:authorization_id{
"client": { "id": "…", "name": "Acme Analytics", "logoUri": "…", "uri": "…" },
"scope": ["openid", "email"],
"autoApproved": false,
"redirect": { "uri": "…" }
}autoApproved é true quando este usuário já concedeu exatamente esses escopos
a este cliente. Não renderize nada e complete o fluxo — pedir de novo uma
permissão que alguém já deu ensina as pessoas a clicarem em telas de
consentimento sem ler.
Depois registre a decisão:
POST /oauth/authorizations/:authorization_id/consent
{ "action": "approve" } // ou "deny"De um jeito ou de outro a resposta carrega o URI para onde mandar o navegador. Em
approve ele leva o código; em deny leva error=access_denied. Sua página não
monta essa URL — ela redireciona para a que recebeu.
Esta requisição é autenticada
Ler e responder uma autorização exigem a sessão do usuário logado. É isso que
amarra o consentimento a uma pessoa. Se sua página de consentimento é alcançável
deslogado, mande o usuário para o login primeiro e traga-o de volta com o
authorization_id intacto.
5. A requisição de token
POST /oauth/token
{
"grant_type": "authorization_code",
"code": "…",
"redirect_uri": "https://acme.example.com/callback",
"code_verifier": "…",
"client_id": "…",
"client_secret": "…"
}O código é de uso único e vida curta. O code_verifier precisa gerar o
code_challenge do passo 1 — isso é PKCE, e é o que torna um código interceptado
inútil para qualquer outro.
{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "…",
"id_token": "…"
}id_token aparece só quando openid estava entre os escopos.
6. Renovando
POST /oauth/token
{ "grant_type": "refresh_token", "refresh_token": "…", "client_id": "…" }Mesmo endpoint, outro grant. O usuário não participa — que é exatamente por que refresh tokens merecem o cuidado de armazenamento que você daria a uma senha.
O que o usuário vê
Escrito assim, tudo são quatro carregamentos de página: o cliente, sua tela de consentimento, de volta ao cliente, pronto. Se sua tela for rápida e parecer com o resto do seu produto, a maioria das pessoas nem vai registrar que saiu dele.