Tokens e escopos
Metade da confusão com OAuth se desfaz ao separar quatro artefatos que parecem a mesma coisa mas têm funções distintas: o authorization code, o access token, o refresh token e, quando entra o OpenID Connect, o ID token. Por cima de todos, os escopos limitam o que cada acesso alcança.
Authorization code
Section titled “Authorization code”O authorization code é uma credencial efêmera e de uso único. Ele chega ao cliente por um redirect do navegador e é logo trocado, no endpoint de token, pelos tokens de verdade. A indireção tem um motivo: ela mantém os tokens fora do canal do navegador. O code viaja pelo front channel (a URL do redirect, visível ao navegador), e os tokens viajam pelo back channel (uma chamada servidor-a-servidor, direta). O code fica atrelado ao client_id, à redirect_uri e ao code_challenge do PKCE, dura poucos minutos (o recomendado é no máximo dez) e serve uma vez só. Depois disso é lixo.
Access token
Section titled “Access token”O access token é a chave que o cliente apresenta ao resource server para obter o dado. A RFC 6749 o define como “uma string que representa uma autorização”. Ele é curto de propósito, com validade na casa de minutos a uma hora, para limitar o estrago caso vaze. Duas propriedades definem como tratá-lo. A primeira: ele costuma ser um bearer token (RFC 6750), o que significa que quem o porta pode usá-lo, como dinheiro em espécie, sem prova adicional de identidade. Daí HTTPS em tudo e vida curta. A segunda: ele é opaco para o cliente, que não deve interpretá-lo nem depender do seu formato; o token faz sentido para o AS e o RS, não para o app que o carrega.
Por baixo, ele assume uma de duas formas, e o cliente não precisa saber qual. Pode ser opaco, uma string aleatória que o RS valida perguntando ao AS, ou um JWT, autossuficiente e assinado, que o RS valida checando a assinatura sem uma ida ao AS. Em qualquer caso, o cliente o envia ao RS num cabeçalho: Authorization: Bearer <token>. Esse cabeçalho é o único caminho aceito na 2.1; pôr o token na query string da URL é proibido, pela mesma razão que derrubou o grant implícito.
Refresh token
Section titled “Refresh token”Access tokens expiram rápido, e ninguém quer o usuário reconsentindo a cada hora. O refresh token é a credencial longeva que o cliente devolve ao endpoint de token do AS para cunhar um access token novo, sem interação do usuário. A disciplina central é uma: ele vai só ao authorization server, nunca ao resource server. A divisão em dois tokens é a troca inteira: o access token curto encolhe o raio de dano de um vazamento; o refresh token longo mantém a experiência tolerável, mas confinado ao AS. Na 2.1, o refresh token de um cliente público precisa ser sender-constrained (atado a uma chave que o cliente prova possuir) ou rotacionado a cada uso, de modo que um roubado funcione no máximo uma vez, detalhe que a página de mudanças explica.
ID token: a fronteira com a identidade
Section titled “ID token: a fronteira com a identidade”O ID token pertence ao OpenID Connect, não ao OAuth puro, mas cabe aqui para marcar a fronteira. Ele é um JWT assinado que o AS entrega ao cliente ao lado do access token, e responde justamente à pergunta que o OAuth se recusa a responder: quem é o usuário. O contraste com o access token é o ponto que evita o erro mais comum.
| Access token | ID token | |
|---|---|---|
| Serve para | autorização (acessar a API) | autenticação (saber quem é o usuário) |
| Quem consome | o resource server | o próprio client |
| Formato | opaco ou JWT | sempre um JWT assinado |
| O client deve lê-lo? | não, é opaco para ele | sim, é o objetivo dele |
| Conteúdo | permissões e escopos | claims de identidade (sub, iss, aud, email) |
O bug clássico é usar um access token para “logar o usuário”. O access token não é endereçado ao cliente e nada afirma de confiável sobre identidade; o ID token é exatamente isso, um token endereçado ao cliente cujo conteúdo é a identidade verificada. Trocar um pelo outro é confundir “consegui abrir a porta” com “sei quem abriu”.
Escopos e consentimento
Section titled “Escopos e consentimento”O escopo é o mecanismo que limita o que um token alcança. O cliente pede escopos na requisição ao /authorize, no parâmetro scope, como uma lista de strings separadas por espaço e sensíveis a maiúsculas que cada serviço define por conta própria (photos, repo, contacts.read). O AS mostra esses escopos ao usuário na tela de consentimento (“este app quer ler suas fotos e seu e-mail”), e o usuário aprova ou nega. O token que sai fica restrito ao que foi concedido, que pode ser menos do que se pediu. A regra é o menor privilégio: peça só o que você usa, porque cada escopo a mais é dano a mais se o token vazar. Quando o concedido difere do pedido, a resposta de token devolve um campo scope para o cliente saber o que de fato recebeu.
Com os artefatos catalogados, falta vê-los em movimento. É o que a página de fluxos faz, seguindo um code do /authorize até virar um access token no cabeçalho de uma chamada à API.
Palavras-chave
Section titled “Palavras-chave”Artefatos: authorization code, access token, refresh token, ID token, bearer token, JWT Conceitos: front channel vs back channel, token opaco, rotação de refresh token, sender-constrained, escopo, consentimento, menor privilégio Padrões: RFC 6750, RFC 6749, OpenID Connect