diff --git a/docs/modules/ROOT/pages/protocol-endpoints.adoc b/docs/modules/ROOT/pages/protocol-endpoints.adoc index 6f244c11..2e640485 100644 --- a/docs/modules/ROOT/pages/protocol-endpoints.adoc +++ b/docs/modules/ROOT/pages/protocol-endpoints.adoc @@ -266,6 +266,71 @@ The supported https://datatracker.ietf.org/doc/html/rfc6749#section-1.3[authoriz * `*AuthenticationSuccessHandler*` -- An internal implementation that handles an `OAuth2AccessTokenAuthenticationToken` and returns the `OAuth2AccessTokenResponse`. * `*AuthenticationFailureHandler*` -- An `OAuth2ErrorAuthenticationFailureHandler`. +[[oauth2-token-endpoint-customizing-client-credentials-grant-request-validation]] +=== Customizing Client Credentials Grant Request Validation + +`OAuth2ClientCredentialsAuthenticationValidator` is the default validator used for validating specific OAuth2 Client Credentials Grant request parameters. +The default implementation validates the `scope` parameter. +If validation fails, an `OAuth2AuthenticationException` is thrown. + +`OAuth2ClientCredentialsAuthenticationProvider` provides the ability to override the default request validation by supplying a custom authentication validator of type `Consumer` to `setAuthenticationValidator()`. + +[TIP] +`OAuth2ClientCredentialsAuthenticationContext` holds the `OAuth2ClientCredentialsAuthenticationToken`, which contains the OAuth2 Client Credentials Grant request parameters. + +[IMPORTANT] +If validation fails, the authentication validator *MUST* throw `OAuth2AuthenticationException`. + +The following example shows how to configure `OAuth2ClientCredentialsAuthenticationProvider` with a custom authentication validator that overrides the default `scope` validation: + +[source,java] +---- +@Bean +public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = + new OAuth2AuthorizationServerConfigurer(); + http.apply(authorizationServerConfigurer); + + authorizationServerConfigurer + .tokenEndpoint(tokenEndpoint -> + tokenEndpoint + .authenticationProviders(configureAuthenticationValidator()) + ); + + return http.build(); +} + +private Consumer> configureAuthenticationValidator() { + return (authenticationProviders) -> + authenticationProviders.forEach((authenticationProvider) -> { + if (authenticationProvider instanceof OAuth2ClientCredentialsAuthenticationProvider) { + Consumer authenticationValidator = + new CustomScopeValidator(); + + // Override default scope validation + ((OAuth2ClientCredentialsAuthenticationProvider) authenticationProvider) + .setAuthenticationValidator(authenticationValidator); + } + }); +} + +static class CustomScopeValidator implements Consumer { + + @Override + public void accept(OAuth2ClientCredentialsAuthenticationContext authenticationContext) { + OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication = + authenticationContext.getAuthentication(); + + Set requestedScopes = clientCredentialsAuthentication.getScopes(); + RegisteredClient registeredClient = authenticationContext.getRegisteredClient(); + Set allowedScopes = registeredClient.getScopes(); + + // TODO Implement scope validation + + } +} +---- + [[oauth2-token-introspection-endpoint]] == OAuth2 Token Introspection Endpoint