Skip to content

Add ClientRegistration.clientSettings.requireProofKey to Enable PKCE #16382

Closed
@rwinch

Description

@rwinch

PKCE is recommended to prevent CSRF and authorization code injection attacks. We should further simplify enabling PKCE for Confidential Clients.

Current Behavior

The simplest Spring Boot application that requires PKCE is shown below:

@Bean
SecurityFilterChain springSecurity(HttpSecurity http, OAuth2AuthorizationRequestResolver resolver) throws Exception {
	http
		.authorizeHttpRequests( r -> r
			.anyRequest().authenticated()
		)
		.oauth2Login(l -> l
			.authorizationEndpoint(a -> a
				.authorizationRequestResolver(resolver)
			)
		);
	return http.build();
}

@Bean
OAuth2AuthorizationRequestResolver pkceResolver(ClientRegistrationRepository clientRegistrationRepository) {
	DefaultOAuth2AuthorizationRequestResolver resolver = 
		new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository,"/oauth2/authorization");
	resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
	return resolver;
}

Shortcomings

This will be simplified to just a Bean declaration when gh-16380 is implemented, but this still has the following downsides:

  • It is not discoverable from the configuration of a typical Spring Security application
  • It is not declarative

For something that is considered a best security practice (rather than an edge case), we must do better.

Solution

I think what makes the most sense is adding a property ClientRegistration.clientSettings.requireProofKey=(true|false) (default is false) similar to what was proposed in gh-12219.

UPDATE After speaking with @jgrandja offline, he suggested the property ClientRegistration.clientSettings.requireProofKey=(true|false) to align with Autorization Server's RegisteredClient.[clientSettings](https://github.com/spring-projects/spring-authorization-server/blob/1.4.1/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java#L73).requireProofKey. In this case, we can introduce the ClientSettings in the same package as ClientRegistration and it does NOT need to be backed by a Map or extend AbstractSettings. If needed, we can later introduce AbstractSettings and back it by a Map at that point.

Note that this is on the ClientRegistration because this is how Spring Security decides which grant type to use. If a single application has multiple grant types for the same provider (or different providers), then it is possible that PKCE is not even valid for a specific registration.

This also has the advantage of making it simple for users to define a property using Spring Boot to declaratively enable PKCE with Spring Security.

Previous Discussions

Perhaps this is no longer a problem, but I wanted to bring it up proactively. I know that this was previously declined because:

  • PKCE is only applicable for authorization_code, so there was hesitation around introducing a PKCE property. I do not find this a valid argument. Spring Security already has properties that are only used for specific grant types and custom validation based upon the grant type. For example, the authorizationUri and tokenUri only make sense for the authorization_code grant type and not for client_credentials. A property for enabling PKCE is just another property, that is validated differently by the grant type.
  • Enabling PKCE makes more sense with Spring Boot auto-configuration. However, Spring Boot rejected the proposal.
  • There are concerns that PKCE may not be something that is configured per client. I'd argue that it needs to be per registration because this is how Spring Security decides which grant type to use. If a single application has multiple grant types for the same provider (or different providers), then it is possible that PKCE is not even valid for a specific registration.

cc @jgrandja @sjohnr

Metadata

Metadata

Assignees

Labels

in: oauth2An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions