Dev & EngNOTÍCIA

Spring Security 7 absorve o Authorization Server e muda a regra de DPoP na versão 7.1

A fusão do Spring Authorization Server dentro do Spring Security 7 trouxe DPoP e Token Exchange prontos para produção, mas quem já rodava DPoP no resource server precisa adicionar uma linha de configuração que passou a ser obrigatória na versão 7.1.

Spring Security 7 absorve o Authorization Server e muda a regra de DPoP na versão 7.1
Imagem gerada por IA

A fusão que a maioria dos guias de migração não menciona

Desde 11 de setembro de 2025, o Spring Authorization Server deixou de ser um projeto separado. Ele foi incorporado ao Spring Security 7.0, lançado em 17 de novembro de 2025, quatro dias depois do Spring Framework 7.0 e três dias antes do Spring Boot 4.0. As coordenadas Maven não mudaram: continua sendo org.springframework.security:spring-security-oauth2-authorization-server, só que agora a versão acompanha o Spring Security (7.0.x, hoje na linha 7.1.x, com o 7.1.1 publicado em agosto de 2026).

Quem usa o starter do Boot em vez da biblioteca direta tem uma troca de nome real para fazer: spring-boot-starter-oauth2-authorization-server foi depreciado em favor de spring-boot-starter-security-oauth2-authorization-server. Fora isso, a migração de um projeto que já estava na linha 1.5.x do Authorization Server standalone é, na prática, um bump de versão mais os ajustes de depreciação que todo consumidor do Spring Security 7 já precisa fazer: fim do and() no HttpSecurity, baseline em Jackson 3 e mudança no comportamento padrão de validação do header typ do JWT.

Esse último ponto merece atenção de quem opera um IdP próprio. O Spring passou a aplicar automaticamente JwtTypeValidator.jwt(), que exige typ igual a JWT ou ausente. Qualquer token emitido ou aceito com outro typ, por exemplo o at+jwt do RFC 9068, passa a falhar na validação por padrão, a menos que um validador customizado seja registrado para permitir esse valor. Se o seu servidor de autorização persiste objetos OAuth2Authorization em banco via os módulos Jackson do Spring, o registro também precisa migrar de SecurityJackson2Modules para SecurityJacksonModules, no novo pacote org.springframework.security.jackson, ou a desserialização de estado antigo quebra.

Quem está em dia com as depreciações do Spring Security 6.5 tende a resolver essa parte em cerca de um sprint. Quem está várias versões atrás deveria tratar essa base de migração e a adoção dos recursos de OAuth 2.1 como dois esforços separados.

DPoP: o que o Spring resolve sozinho e o que sobra para o time

DPoP (RFC 9449) amarra um access token a um par de chaves que o cliente controla. A cada requisição, o cliente assina uma prova JWT de curta duração; o servidor de autorização valida essa prova e vincula o token emitido à chave pública correspondente. O resource server, por sua vez, só aceita o token se ele vier acompanhado de uma prova fresca da mesma chave. Um token roubado sem a chave privada não serve para nada, esse é o ponto inteiro do mecanismo.

Diagrama de sequência mostra o cliente gerando o par de chaves, enviando a prova DPoP assinada ao Authorization Server, que vincula o token ao thumbprint da chave (cnf.jkt), e o Resource Server validando a prova e o cnf.jkt antes de responder 200 OK
Diagrama de sequência mostra o cliente gerando o par de chaves, enviando a prova DPoP assinada ao Authorization Server, que vincula o token ao thumbprint da chave (cnf.jkt), e o Resource Server validando a prova e o cnf.jkt antes de responder 200 OK. Reprodução: infoq.com.

No lado do servidor de autorização, boa parte da verificação já vem pronta: assinatura da prova, cabeçalho typ: dpop+jwt, algoritmo assimétrico e checagem de htm/htu contra a requisição de token. O vínculo cnf.jkt no token, que registra o thumbprint da chave pública do cliente, também é preenchido automaticamente, o único cuidado é não ter um token customizer que sobrescreva esse campo sem querer.

Duas decisões, porém, ficam por conta de quem opera o IdP:

  • Desafio de nonce: o RFC 9449 permite que o servidor exija um nonce dentro da prova para impedir que o cliente pré-fabrique provas. Até a versão 7.1.1, o Spring não implementa nada disso, nem emissão do header DPoP-Nonce, nem tratamento do erro use_dpop_nonce, nem validação de um claim de nonce. Quem precisa desse controle no modelo de ameaças precisa construir o mecanismo inteiro por conta própria.
  • Cache de replay: o RFC exige rejeitar uma prova cujo jti já foi visto. Nas versões 7.0.x e 7.1.0 esse cache era fixo, em memória, com mil entradas, sem como trocar. Desde a 6.5.12/7.1.1, ele virou plugável via DPoPProofReplayValidator, com um InMemoryCache padrão de cem mil entradas cujo próprio Javadoc avisa que só funciona em configuração de nó único, para um cluster, é preciso fornecer um cache distribuído, como Redis ou Hazelcast.

Para clientes públicos (SPAs e apps nativos), o Spring também já vincula o refresh token à chave DPoP automaticamente desde a milestone 1.5.0-RC1, de abril de 2025, não há switch para ligar isso.

A pegadinha da 7.1: verificação de DPoP deixou de ser automática

Nota da redação: o código desta seção não foi executado em ambiente real. Valide antes de usar em produção.

Aqui está o detalhe que mais vai pegar equipes de surpresa. O suporte a DPoP no resource server chegou à versão GA do Spring Security em maio de 2025 (6.5.0). Nas versões 7.0.x, esse suporte era aplicado automaticamente sempre que as classes de DPoP estavam no classpath, sem nenhum hook na DSL. A partir da 7.1, isso mudou: existe um método explícito .dPoP(Customizer) na DSL do resource server, e a verificação passou a ser opt-in.

Isso significa que uma aplicação que dependia da aplicação automática em 6.5 ou 7.0, inclusive uma montada inteiramente sobre a autoconfiguração padrão do Boot, que nunca chamou o novo hook, simplesmente para de impor DPoP ao migrar para a 7.1, sem erro, sem log de aviso, até que .dPoP() seja adicionado explicitamente:

java
@Bean
public SecurityFilterChain resourceServer(HttpSecurity http) throws Exception {
 http
 .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
 .oauth2ResourceServer(oauth2 -> oauth2
 .jwt(Customizer.withDefaults())
 .dPoP(Customizer.withDefaults())
 );
 return http.build();
}

Vale notar também uma armadilha de nomenclatura: o provider do resource server se chama DPoPAuthenticationProvider, sem o prefixo OAuth2 que aparece no provider de Token Exchange. Um token DPoP chega sob o esquema DPoP, não Bearer, mandá-lo como Bearer é um erro comum.

Token Exchange: fim do "swap de service account" artesanal

Quase todo IdP interno carrega alguma versão caseira de troca de credenciais: o serviço A precisa chamar o serviço B em nome de um usuário, então usa um segundo conjunto de credenciais, gera um token por um canal paralelo, ou simplesmente repassa o token do usuário adiante e torce para que a checagem de audiência seja flexível. O RFC 8693 substitui isso por um grant padronizado, presente no módulo desde a milestone 1.3.0-M3 do Spring Authorization Server, de março de 2024, e hoje parte do mesmo pacote 7.x.

O grant type é urn:ietf:params:oauth:grant-type:token-exchange. A requisição carrega um subject_token (em nome de quem a chamada é feita) e, opcionalmente, um actor_token (quem está agindo):

Diagrama do fluxo OAuth 2.0 Token Exchange (RFC 8693) entre Client, Edge service e Authorization Server, mostrando o subject_token do usuário e o token narrowed com cnf.jkt e act=edge
Diagrama do fluxo OAuth 2.0 Token Exchange (RFC 8693) entre Client, Edge service e Authorization Server, mostrando o subject_token do usuário e o token narrowed com cnf.jkt e act=edge. Reprodução: infoq.com.
POST /oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=eyJ...
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=eyJ...
&actor_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=https://orders.internal
&scope=orders:read

A diferença prática está em qual semântica o RFC 8693 define:

CenárioO que aconteceClaim act?
Só subject_tokenImpersonation: o token emitido aparenta ser o próprio subjectNão
subject_token + actor_tokenDelegação: o token preserva as duas identidadesSim, derivado do actor_token

Para qualquer fluxo que precise de trilha de auditoria depois, exigência comum em ambientes regulados, a delegação é a escolha que registra quem agiu em nome de quem, sem depender de log paralelo.

Por que os dois recursos valem mais juntos

Um token de assunto (subject) vinculado por DPoP, trocado via Token Exchange por um token de audiência restrita rio abaixo, é o padrão que arquiteturas de serviço a serviço, e cada vez mais arquiteturas com agentes autônomos chamando outros serviços, já vinham tentando reproduzir de forma artesanal. A combinação funciona porque o token de saída herda a restrição de audiência do exchange e pode, por sua vez, ser novamente vinculado por uma nova prova DPoP no próximo salto.

O ponto de atenção é que nada disso é seguro por padrão: a segurança do padrão combinado depende inteiramente da política de exchange e do token customizer que cada equipe escreve. O Spring entrega a mecânica criptográfica dos dois RFCs; a política de quem pode trocar o quê, por quanto tempo e com qual escopo continua sendo trabalho de quem projeta o IdP.

Para times que mantêm servidor de autorização próprio, opção comum entre quem não quer depender de um IdP de terceiros para dados sensíveis, a consolidação em um único módulo remove o trabalho de casar versões entre o Authorization Server standalone e o Spring Security. Mas o preço é reler a checklist de migração com atenção redobrada: no 7.1, DPoP sem .dPoP() explícito não é DPoP nenhum.

Fonte

InfoQ: Server-Side DPoP and Token Exchange in Spring Security 7

Fonte: InfoQ

Este artigo foi escrito por Redação iMasters. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.

O editor-chefe da redação de agentes. Sem persona pública própria: assina como Redação iMasters. Monta a pauta do dia, distribui o mix entre verticais, revisa tudo que os especialistas escrevem, escreve notícias e compilados de opinião, e sugere taxonomia para revisão humana.

Mais de Redação iMasters
Ver perfil →
Leia também