Skip to content

Fluxos

As personas e os tokens só ganham vida dentro de um fluxo, o que a spec chama de grant type: a coreografia que leva do “quero acesso” ao token na mão. O OAuth 2.1 mantém uma lista curta de grants, cada um para uma situação. O que você vai encontrar na esmagadora maioria das vezes é o Authorization Code com PKCE; os outros cobrem serviço-a-serviço, aparelhos sem entrada de texto e a renovação de um token expirado.

Este é o fluxo canônico, para qualquer cliente que age em nome de um usuário, seja ele um app web, uma SPA, um app de celular ou uma CLI. O PKCE (lê-se “pixy”, de Proof Key for Code Exchange) é a prova por requisição que substitui o segredo que falta ao cliente público, e na 2.1 ele é obrigatório para todos.

sequenceDiagram
    participant RO as Resource Owner
    participant C as Client
    participant AS as Authorization Server
    participant RS as Resource Server
    C->>C: gera code_verifier e deriva code_challenge
    C->>AS: GET /authorize com code_challenge e state
    AS->>RO: pede login e consentimento
    RO->>AS: aprova os escopos
    AS->>C: redirect com authorization code e state
    C->>AS: POST /token com code e code_verifier
    AS->>AS: confere o code_verifier contra o code_challenge
    AS->>C: access_token mais refresh_token
    C->>RS: chamada com Authorization Bearer
    RS->>C: recurso protegido

Passo a passo, o que cada seta carrega.

Antes de tudo, o cliente gera um segredo só seu para aquela requisição. Ele sorteia um code_verifier, uma string aleatória de 43 a 128 caracteres, e dela deriva um code_challenge. No método S256, o único que se deve usar, o desafio é o hash do verificador: code_challenge = BASE64URL(SHA256(code_verifier)).

Com isso em mãos, o cliente redireciona o navegador do usuário ao endpoint /authorize do AS, passando o desafio (não o verificador):

https://authorization-server.com/authorize?response_type=code
&client_id=s6BhdRkqt3
&redirect_uri=https://app.exemplo.com/callback
&scope=photos
&state=xyz123
&code_challenge=E9Melhoa2CwvinuxlnA4hg...
&code_challenge_method=S256

O state é um valor aleatório contra CSRF, que o cliente vai conferir na volta; o code_challenge viaja agora, o code_verifier fica guardado. O AS então autentica o usuário e mostra a tela de consentimento com os escopos pedidos. Aprovado, ele redireciona de volta à redirect_uri com o code e o mesmo state. O cliente confere que o state bate (senão, descarta) e parte para a troca.

A troca acontece pelo back channel, um POST direto ao endpoint /token, sem passar pelo navegador:

POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.exemplo.com/callback
&client_id=s6BhdRkqt3
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r...

Aqui está o pulo do gato do PKCE: o cliente envia agora o code_verifier original. O AS refaz o hash desse verificador e compara com o code_challenge que guardou na etapa do /authorize. Só se baterem ele emite os tokens (um cliente confidencial ainda apresenta o client_secret por cima). A resposta é um JSON:

{
"access_token": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"scope": "photos"
}

De posse do access token, o cliente chama a API do resource server pondo o token no cabeçalho Authorization: Bearer ..., e recebe o recurso.

O que o PKCE defende é a interceptação do authorization code. Num cliente público, um app malicioso registrado no mesmo esquema de redirect pode capturar o code na volta. Sem PKCE, o code roubado bastaria para obter tokens. Com PKCE, o atacante também precisaria do code_verifier, que nunca saiu do cliente legítimo e nunca trafegou pelo navegador, então o code interceptado não vale nada.

Quando não há usuário nenhum na história, e um serviço fala com outro em seu próprio nome, o fluxo é o Client Credentials. Um backend que consome a API de outro sistema como ele mesmo, um job que roda de madrugada. Só clientes confidenciais o usam, porque ele se apoia num segredo. O cliente faz um POST ao /token com grant_type=client_credentials e se autentica com client_id e client_secret:

POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=s6BhdRkqt3
&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
&scope=reports.read

Não há tela de consentimento (não há usuário para consentir) e, por convenção, não se emite refresh token: quando o access token expira, o cliente simplesmente roda o grant de novo, já que sempre pode se autenticar.

Para aparelhos com internet mas sem teclado ou navegador decentes, uma smart TV, um console, uma CLI, o Device Authorization move o consentimento para um segundo aparelho. O aparelho pede um par de códigos ao AS e recebe algo como:

{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNh",
"user_code": "WDJB-MJHT",
"verification_uri": "https://exemplo.com/device",
"expires_in": 1800,
"interval": 5
}

A TV exibe “acesse exemplo.com/device e digite WDJB-MJHT” (o user_code), enquanto usa o device_code para consultar o endpoint de token de tempos em tempos, respeitando o interval. Enquanto o usuário não termina no celular, o AS responde authorization_pending; se o aparelho consultar rápido demais, slow_down. Assim que o usuário aprova, a próxima consulta recebe um token normal.

Quando o access token expira, o Refresh Token o renova sem incomodar o usuário. O cliente faz um POST ao /token com grant_type=refresh_token e o refresh token que guardou; pode pedir um escopo igual ou menor, nunca maior. Sob rotação, a resposta traz também um refresh token novo, que invalida o anterior. Na 2.1 essa rotação (ou o sender-constraining) é obrigatória para clientes públicos, pela razão que a página de mudanças explica.

A escolha cai naturalmente da situação, e é quase sempre óbvia.

SituaçãoFluxo
App (web, SPA, celular, desktop, CLI) agindo por um usuárioAuthorization Code + PKCE
Serviço falando com serviço, sem usuárioClient Credentials
Aparelho sem teclado ou navegadorDevice Authorization
Renovar um access token expiradoRefresh Token

Faltam dois grants que existiam na 2.0 e você não vai achar aqui: o implícito e o de senha. A ausência é deliberada, e a página seguinte conta por que ambos foram removidos.

Fluxos: authorization code, PKCE, client credentials, device authorization, refresh token Parâmetros: response_type=code, code_challenge, code_challenge_method=S256, code_verifier, grant_type, state, scope Endpoints: /authorize, /token Conceitos: front channel, back channel, interceptação de code, rotação de token