Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify configuration of OAuth2 Client component model #11783

Closed
wujek-srujek opened this issue Sep 4, 2022 · 6 comments
Closed

Simplify configuration of OAuth2 Client component model #11783

wujek-srujek opened this issue Sep 4, 2022 · 6 comments
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement
Milestone

Comments

@wujek-srujek
Copy link

Expected Behavior

I would like an easy way to add custom parameters for authorization and token requests.

Current Behavior

Currently it is possible but very difficult and verbose. It is also documented badly without a single example, e.g. https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorization-grants.html#oauth2Client-client-creds-grant only says what to do (more or less) but the whole page is missing examples.

Context

A similar issue is #7379.
I am using Auth0 which requires a custom request parameter audience for the client_credentials grant. It is currently possible but very hard (it took me some time to figure out what to do, and I'm not even sure if this is correct, but it works) and verbose to add this parameter with Spring Security:

val converter = OAuth2ClientCredentialsGrantRequestEntityConverter()
converter.addParametersConverter {
    LinkedMultiValueMap<String, String>().apply {
        this["audience"] = "xyz_value" // <=== All I want to do is this.
    }
}

val client = DefaultClientCredentialsTokenResponseClient()
client.setRequestEntityConverter(converter)

val clientProvider = OAuth2AuthorizedClientProviderBuilder
    .builder()
    .clientCredentials { it.accessTokenResponseClient(client) }
    .build()

val manager = DefaultOAuth2AuthorizedClientManager(
    clientRegistrationRepository, authorizedClientRepository,
)
manager.setAuthorizedClientProvider(clientProvider)

val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(manager)

The only real valuable change is one line which adds the parameter, but to make it work I need to add a lot of code around it. The written code is pretty much a copy of what Spring Security would do itself. However, I don't even think the code above is equivalent to creating a ServletOAuth2AuthorizedClientExchangeFilterFunction with a ClientRegistrationRepository and OAuth2AuthorizedClientRepository as that constructor also sets up an AuthorizationFailureForwarder, which my code doesn't. If I wanted to also do that I would need to copy even more code from the depths of Spring Security.

The difficulty seems to stem from the fact that all of the objects needed are instantiated internally and not dependency injected. For example, the ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository, authorizedClientRepository) constructor internally creates an DefaultOAuth2AuthorizedClientManager with all the possible clients, but it is impossible to change them in any way, without pretty much rebuilding everything on my own.

(If I'm wrong and it is indeed possible, awesome, please show me how to limit the amount of code above.)

I'm thinking about making it possible to define a OAuth2ClientCredentialsGrantRequestEntityConverter @Bean whose instances would be looked up and applied when a request is built. Or maybe even just the 'parametersConverters', which are @Ordered and lookup up and applied?

@wujek-srujek wujek-srujek added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Sep 4, 2022
@sjohnr sjohnr added the in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) label Sep 9, 2022
@jgrandja
Copy link
Contributor

@wujek-srujek I agree that we could do more to simplify the configuration and customization of the OAuth2 Client component model.

Please keep in mind that the component design of OAuth2AuthorizedClientManager, OAuth2AuthorizedClientProvider, OAuth2AccessTokenResponseClient, etc... provide many different configuration options available depending on what part of the flow you are looking to customize, for example, token request and/or response, success/failure handling, authorization grant support, etc. The flexibility is there in the design but yes it can become verbose to configure.

gh-8882 was an attempt to address this but we ran into a couple of issues so it's been on hold. However, after we get 6.0 released, this will be one of our main priorities to allow for easier configuration of the OAuth2 Client component model.

I'll change the title of this issue to align with the goal of providing an easier way to configure. Hopefully, we can gather more feedback from the community on suggestions to make it easier.

@jgrandja jgrandja removed their assignment Sep 14, 2022
@jgrandja jgrandja removed the status: waiting-for-triage An issue we've not yet triaged label Sep 14, 2022
@jgrandja jgrandja changed the title Simplify customization of access token requests (possibly also authorization requests) Simplify configuration of OAuth2 Client component model Sep 14, 2022
@jgrandja
Copy link
Contributor

Related gh-8882

@jzheaux
Copy link
Contributor

jzheaux commented May 20, 2023

It think a happy medium would be to focus on the provider itself, like so:

@Bean
public OAuth2AuthorizedClientProvider authorizedClientProvider() {
    var jwtBearer  = new JwtBearerOAuth2AuthorizedClientProvider();
    jwtBearer.setClockSkew(Duration.ofMinutes(2));
    return jwtBearer;
}

It seems like this is already the pattern that is encouraged by the fact that OAuth2ClientConfiguration looks for the other components of OAuth2AuthorizedClientManager as beans.

I think it would be good to further simplify this configuration by also deprecating the lookup of OAuth2AccessTokenResponseClient for client credentials since this is a couple of layers of configuration deep. Instead, I think it would be better for folks to do:

@Bean
public OAuth2AuthorizedClientProvider authorizedClientProvider() {
    var clientCredentials  = new ClientCredentialsOAuth2AuthorizedClientProvider();
    clientCredentials.setAccessTokenResponseClient(custom);
    return clientCredentials;
}

Spring Security could pick up a list of OAuth2AuthorizedClientProvider beans and publish a delegator:

@Bean
public OAuth2AuthorizedClientProvider clientCredentials() {
    var clientCredentials  = new ClientCredentialsOAuth2AuthorizedClientProvider();
    clientCredentials.setAccessTokenResponseClient(custom);
    return clientCredentials;
}

@Bean
public OAuth2AuthorizedClientProvider authorizationCode() {
    return new AuthorizationCodeOAuth2AuthorizedClientProvider();
}

Or, for more configuration guidance, folks could still use OAuth2AuthorizedClientProviderBuilder like so:

@Bean
public OAuth2AuthorizedClientProvider authorizedClientProvider() {
    return OAuth2AuthorizedClientProviderBuilder.builder()
        .authorizationCode().clientCredentials((client) -> client.accessTokenResponseClient(custom))
        .build();
}

@BALANIVEDHITHA
Copy link

Looking forward towards this implementation ! Especially in the scenario where we have to add audience to our request .

@sjohnr
Copy link
Member

sjohnr commented Sep 6, 2023

Hi folks. I wasn't able to put an update on this issue due to SpringOne happening simultaneously, but better late than never. A blog post went out a few weeks ago with examples of what you can try out in the latest milestone release (6.2.0-M2) related to this issue.

Next steps include updating the reference documentation with examples that cover simplified configuration, similar to what @jzheaux referenced above. I'd love for anyone following this issue to try out the milestone and give feedback. Again, see the blog post for some examples, or keep an eye on this page of the docs (now updated) for the 6.2 release. Note that we've focused on servlet support for 6.2, and similar reactive configuration improvements will be added in a future release with gh-13763.

@sjohnr sjohnr added this to the 6.2.0 milestone Sep 20, 2023
@sjohnr
Copy link
Member

sjohnr commented Sep 20, 2023

As mentioned above, the remaining task for this release is to finish updates to the documentation via gh-13785. I'm going to close this issue for tracking purposes, as gh-13763 will be used to add reactive support in a future release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement
Projects
Archived in project
Development

No branches or pull requests

5 participants