Spring Security 7 absorbs the Authorization Server and changes the DPoP rule in version 7.1
The merger of Spring Authorization Server into Spring Security 7 brought DPoP and Token Exchange ready for production, but anyone who was already running DPoP on the resource server needs to add a configuration line that became mandatory in version 7.1.

The merger that most migration guides don't mention
Since September 11, 2025, Spring Authorization Server has no longer been a separate project. It was incorporated into Spring Security 7.0, released on November 17, 2025, four days after Spring Framework 7.0 and three days before Spring Boot 4.0. The Maven coordinates haven't changed: it's still org.springframework.security:spring-security-oauth2-authorization-server, except now the version tracks Spring Security (7.0.x, currently on the 7.1.x line, with 7.1.1 published in August 2026).
Anyone using the Boot starter instead of the library directly has an actual name swap to make: spring-boot-starter-oauth2-authorization-server was deprecated in favor of spring-boot-starter-security-oauth2-authorization-server. Beyond that, migrating a project that was already on the 1.5.x line of the standalone Authorization Server is, in practice, a version bump plus the deprecation adjustments that every Spring Security 7 consumer already needs to make: the end of and() on HttpSecurity, a baseline on Jackson 3, and a change in the default validation behavior of the JWT typ header.
This last point deserves attention from anyone operating their own IdP. Spring now automatically applies JwtTypeValidator.jwt(), which requires typ to equal JWT or be absent. Any token issued or accepted with a different typ, for example the at+jwt from RFC 9068, now fails validation by default unless a custom validator is registered to allow that value. If your authorization server persists OAuth2Authorization objects to a database via Spring's Jackson modules, the registration also needs to migrate from SecurityJackson2Modules to SecurityJacksonModules, in the new org.springframework.security.jackson package, or deserialization of old state breaks.
Anyone who's up to date with the Spring Security 6.5 deprecations tends to resolve this part in about one sprint. Anyone several versions behind should treat this migration baseline and the adoption of the OAuth 2.1 features as two separate efforts.
DPoP: what Spring solves on its own and what's left for the team
DPoP (RFC 9449) binds an access token to a key pair that the client controls. On every request, the client signs a short-lived JWT proof; the authorization server validates that proof and binds the issued token to the corresponding public key. The resource server, in turn, only accepts the token if it comes with a fresh proof from the same key. A stolen token without the private key is useless, that's the entire point of the mechanism.

On the authorization server side, most of the verification already comes built in: proof signature, the typ: dpop+jwt header, asymmetric algorithm, and checking htm/htu against the token request. The cnf.jkt binding in the token, which records the thumbprint of the client's public key, is also filled in automatically; the only thing to watch for is not having a token customizer that overwrites this field by accident.
Two decisions, however, are left to whoever operates the IdP:
- Nonce challenge: RFC 9449 allows the server to require a nonce inside the proof to prevent the client from pre-fabricating proofs. Up to version 7.1.1, Spring implements none of this, neither issuing the
DPoP-Nonceheader, nor handling theuse_dpop_nonceerror, nor validating a nonce claim. Anyone who needs this control in their threat model has to build the entire mechanism themselves. - Replay cache: the RFC requires rejecting a proof whose
jtihas already been seen. In versions 7.0.x and 7.1.0, this cache was fixed, in-memory, with a thousand entries, with no way to change it. Since 6.5.12/7.1.1, it has become pluggable viaDPoPProofReplayValidator, with a defaultInMemoryCacheof one hundred thousand entries, whose own Javadoc warns that it only works in a single-node configuration; for a cluster, you need to provide a distributed cache, such as Redis or Hazelcast.
For public clients (SPAs and native apps), Spring also already binds the refresh token to the DPoP key automatically since milestone 1.5.0-RC1, from April 2025; there's no switch to turn this on.
The catch in 7.1: DPoP verification is no longer automatic
Editor's note: the code in this section was not executed in a real environment. Validate before using it in production.
Here's the detail most likely to catch teams off guard. DPoP support on the resource server reached GA in Spring Security in May 2025 (6.5.0). In the 7.0.x versions, this support was applied automatically whenever the DPoP classes were on the classpath, with no hook at all in the DSL. Starting with 7.1, that changed: there's now an explicit .dPoP(Customizer) method in the resource server DSL, and verification became opt-in.
This means that an application that relied on the automatic application in 6.5 or 7.0, including one built entirely on Boot's default autoconfiguration, which never called the new hook, simply stops enforcing DPoP when migrating to 7.1, with no error, no warning log, until .dPoP() is added explicitly:
@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();
}It's also worth noting a naming trap: the resource server's provider is called DPoPAuthenticationProvider, without the OAuth2 prefix that appears on the Token Exchange provider. A DPoP token arrives under the DPoP scheme, not Bearer; sending it as Bearer is a common mistake.
Token Exchange: the end of the hand-rolled "service account swap"
Almost every internal IdP carries some homegrown version of credential swapping: service A needs to call service B on behalf of a user, so it uses a second set of credentials, generates a token through a parallel channel, or simply passes the user's token along and hopes the audience check is lenient. RFC 8693 replaces this with a standardized grant, present in the module since milestone 1.3.0-M3 of Spring Authorization Server, from March 2024, and today part of the same 7.x package.
The grant type is urn:ietf:params:oauth:grant-type:token-exchange. The request carries a subject_token (on whose behalf the call is made) and, optionally, an actor_token (who is acting):

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:readThe practical difference lies in which semantics RFC 8693 defines:
| Scenario | What happens | act claim? |
|---|---|---|
Only subject_token | Impersonation: the issued token appears to be the subject itself | No |
subject_token + actor_token | Delegation: the token preserves both identities | Yes, derived from the actor_token |
For any flow that needs an audit trail later, a common requirement in regulated environments, delegation is the choice that records who acted on whose behalf, without relying on a parallel log.
Why the two features are worth more together
A subject token bound by DPoP, exchanged via Token Exchange for an audience-restricted token further downstream, is the pattern that service-to-service architectures, and increasingly architectures with autonomous agents calling other services, had already been trying to reproduce by hand. The combination works because the outgoing token inherits the audience restriction from the exchange and can, in turn, be bound again by a new DPoP proof on the next hop.
The point to watch is that none of this is secure by default: the security of the combined pattern depends entirely on the exchange policy and the token customizer that each team writes. Spring delivers the cryptographic mechanics of both RFCs; the policy of who can exchange what, for how long, and with what scope remains the work of whoever designs the IdP.
For teams that maintain their own authorization server, a common choice among those who don't want to depend on a third-party IdP for sensitive data, consolidation into a single module removes the work of matching versions between the standalone Authorization Server and Spring Security. But the price is rereading the migration checklist with redoubled attention: in 7.1, DPoP without an explicit .dPoP() isn't DPoP at all.
Source
InfoQ: Server-Side DPoP and Token Exchange in Spring Security 7
Translated from the Brazilian Portuguese original · Read the original
Researchers find spyware that infects phones via ads with no click at all
Citizen Lab documented for the first time a spying campaign that uses real-time ad auctions to infect devices without any interaction from the victim.





