O que mudou na 2.1
O jeito mais honesto de descrever a 2.1 é que ela não inventa quase nada. Ela pega o OAuth 2.0 (a RFC 6749, de 2012) e uma década de correções de segurança que vinham espalhadas em extensões e recomendações, e as reúne num texto-base único, promovendo a obrigatório o que era opcional e cortando o que se provou inseguro. É por isso que a mudança se lê como uma lista de “passou a valer” e “saiu de cena”, não como um redesenho.
Uma consolidação, não um protocolo novo
Section titled “Uma consolidação, não um protocolo novo”O que a 2.1 junta num documento só: a RFC 6749 (o núcleo do OAuth 2.0), a RFC 6750 (uso de bearer tokens), a RFC 7636 (PKCE), a RFC 8252 (OAuth em apps nativos) e, decisiva, a RFC 9700 (o Security Best Current Practice, publicado em janeiro de 2025). A própria seção de compatibilidade do draft resume a postura: a 2.1 é compatível com a 2.0 com as restrições das boas práticas aplicadas, o que significa exigir o que a 2.0 deixava opcional (como o PKCE) e não especificar o que a 2.0 permitia mas se mostrou frágil (como os grants implícito e de senha).
O que passou a ser obrigatório
Section titled “O que passou a ser obrigatório”PKCE para todo cliente. Na RFC 7636, o PKCE nasceu mirando clientes públicos, que não têm segredo. A 2.1 o torna obrigatório para todo cliente que usa o authorization code, público ou confidencial. Ele fecha a interceptação e a injeção de authorization code: quem rouba um code não consegue trocá-lo por token sem o code_verifier, que nunca sai do cliente legítimo (o passo a passo está nos fluxos). Exigi-lo também dos confidenciais elimina a bifurcação “esse cliente é público ou confidencial?” como fonte de erro de configuração, e cobre o caso em que um code vazado somado a um segredo comprometido bastaria.
Redirect URI com correspondência exata. O AS passa a exigir que a redirect_uri do pedido case, caractere por caractere, com uma URI pré-registrada. A única exceção é o número da porta em redirects de localhost de apps nativos. Correspondência por curinga ou por prefixo abre a porta para open redirect e roubo de code: um padrão como https://app.exemplo.com/*, ou um redirecionamento aberto no mesmo host, deixa o atacante forjar uma URI (https://app.exemplo.com.evil.com/...) que desvia o code para ele.
Refresh token de cliente público contido. O refresh token de um cliente público precisa ser sender-constrained (atado a uma chave que o cliente prova possuir, via DPoP ou mTLS) ou de uso único, com rotação a cada renovação. Um cliente público não consegue proteger uma credencial longeva ao portador; a rotação encurta a janela de um roubo e o torna detectável, porque, se o token rotacionado for reusado, o próprio reuso denuncia o vazamento e permite revogar toda a família de tokens.
Bearer token só no cabeçalho. O access token viaja apenas no cabeçalho Authorization: Bearer, e a 2.1 proíbe pô-lo na query string da URL. A razão é a mesma que condena o fragmento do grant implícito: tokens em URLs acabam no histórico do navegador, no cabeçalho Referer, em logs de servidor e proxy, e em links compartilhados.
O que saiu
Section titled “O que saiu”O grant implícito. Na 2.0, o grant implícito (response_type=token) fazia o AS devolver o access token direto no fragmento da URL de redirect, sem a etapa de troca por code. Era entrega pelo front channel, sem chance de atrelar o token ao cliente que o pediu, e o token no fragmento vaza pelo histórico, pelo Referer, pelos logs, e fica exposto a qualquer script na página (um alvo fácil de XSS). A 2.1 o remove; o substituto é o Authorization Code com PKCE, que mantém o token fora da URL.
O grant de senha (ROPC). No Resource Owner Password Credentials, o cliente coletava usuário e senha da pessoa e os trocava por um token. O problema é estrutural: o cliente manuseia a senha em claro, o que treina o usuário a entregar a senha a terceiros, dá ao cliente acesso total à conta e é incompatível com federação, MFA e consentimento, já que não há etapa de navegador onde um segundo fator ou uma tela de permissão caibam. A RFC 9700 é categórica: esse grant não deve ser usado.
Em uma tabela
Section titled “Em uma tabela”| Mudança | Regra na 2.1 | Ataque que fecha |
|---|---|---|
| PKCE | obrigatório para todo cliente no code grant | interceptação e injeção de authorization code |
| Redirect URI | correspondência exata de string | open redirect e roubo de code |
| Refresh token (público) | sender-constrained ou rotacionado | reuso de refresh token roubado |
| Bearer token | só no cabeçalho Authorization | vazamento por URL (histórico, Referer, logs) |
| Grant implícito | removido | access token exposto no fragmento da URL |
| Grant de senha (ROPC) | removido | cliente manuseando a senha do usuário |
O que isso significa na prática
Section titled “O que isso significa na prática”Se você constrói com Authorization Code mais PKCE e mantém o token no cabeçalho, você já está “na 2.1” sem esforço extra. O que foi removido, no fundo, você não deveria estar usando de qualquer forma. É justamente essa consolidação que permitiu ao MCP dizer apenas “use OAuth 2.1” e herdar os padrões endurecidos de uma vez, sem relitigar cada decisão, que é o tema da próxima página.
Palavras-chave
Section titled “Palavras-chave”Removido: grant implícito, resource owner password credentials, ROPC, bearer token na query string Obrigatório: PKCE para todos, correspondência exata de redirect URI, rotação de refresh token, sender-constrained Padrões: OAuth 2.1, RFC 9700, RFC 6749, RFC 7636, Security BCP