spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

Make requestEntityConverter customisable in RestClientOAuth2AccessTokenResponseClient

Open ThomasVitale opened this issue 2 months ago • 4 comments

Expected Behavior

The AbstractRestClientOAuth2AccessTokenResponseClient class contains five different properties in its internal state:

  • restClient
  • requestEntityConverter
  • headersConverter
  • parametersConverter
  • parametersCustomizer

I expect it would be possible to overwrite any of them when building a new instance of this class.

Current Behavior

The current behaviour is that all those properties are non-final (therefore, mutable), but only 4 out of 5 can be customised via a setter method. The requestEntityConverter cannot be customised.

Context

The requestEntityConverter is a critical part of this class and would need to be customised to support OAuth2 flows that Spring Security doesn't support yet out-of-the-box. For example, in order to support DPoP, I would need to perform the request differently to support the nonce exchange part of the DPoP flow. Because of that, my current workaround is to create a custom class, duplicate all the code from AbstractRestClientOAuth2AccessTokenResponseClient, except for an additional setRequestEntityConverter() method that would allow to customise it to add the header.

Since the requestEntityConverter was designed mutable to begin with, and for consistency with all the other properties in the same class (including other converters), it would be great if a setRequestEntityConverter() could be added to it. If that's something you consider acceptable, I'd be happy to submit a PR for it.

Thanks!

ThomasVitale avatar Oct 29 '25 11:10 ThomasVitale

@ThomasVitale Nice to hear from you.

I would need to perform the request differently to support the nonce exchange part of the DPoP flow ... that would allow to customise it to add the header.

You can add custom headers via addHeadersConverter(). See the reference doc for an example.

Would that work for you?

jgrandja avatar Oct 31 '25 19:10 jgrandja

@jgrandja thanks so much for your answer. My problem is that the DPoP flow requires a double request: the first one might fail and return a nonce, that needs to be included in the request and try that again.

After thinking a bit more about it, I guess that hijacking requestEntityConverter() for that purpose is not the best way to implement the flow. I landed on overriding the getTokenResponse() method directly. Unfortunately, the AbstractRestClientOAuth2AccessTokenResponseClient class cannot really be subclassed due to the package-private constructor, even though the class is public. So I would need to duplicate the entire class to add the second request. Perhaps the constructor (which is empty) could be made public? Or maybe I should just fgo with the full duplication.

Do you have recommendations on how to proceed? Once I get a working solution, I'd be available to contribute it upstream so to have DPoP support also in Spring Security OAuth2 Client.

ThomasVitale avatar Nov 24 '25 08:11 ThomasVitale

My latest suggestion is related to https://github.com/spring-projects/spring-security/issues/18154

ThomasVitale avatar Nov 26 '25 14:11 ThomasVitale

@ThomasVitale

Do you have recommendations on how to proceed?

If you can put together an integration test using this proposed solution (see comment) then we can see what changes are needed to move you forward.

Take a look at

https://github.com/spring-projects/spring-security/blob/7503d8018dc1e59bf809b5349e5a90c92a489f9d/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java#L165

for an example integration test on how to generate the DPoP.

jgrandja avatar Dec 04 '25 11:12 jgrandja