| 
					
				 | 
			
			
				@@ -126,6 +126,129 @@ static class CustomRedirectUriValidator implements Consumer<OAuth2AuthorizationC 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[[oauth2-pushed-authorization-request-endpoint]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+== OAuth2 Pushed Authorization Request Endpoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestEndpointConfigurer` provides the ability to customize the https://datatracker.ietf.org/doc/html/rfc9126#section-2[OAuth2 Pushed Authorization Request endpoint]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+It defines extension points that let you customize the pre-processing, main processing, and post-processing logic for https://datatracker.ietf.org/doc/html/rfc9126#section-2.1[OAuth2 Pushed Authorization requests]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestEndpointConfigurer` provides the following configuration options: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,java] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			OAuth2AuthorizationServerConfigurer.authorizationServer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.with(authorizationServerConfigurer, (authorizationServer) -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			authorizationServer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.pushedAuthorizationRequestEndpoint(pushedAuthorizationRequestEndpoint -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					pushedAuthorizationRequestEndpoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        				.pushedAuthorizationRequestConverter(pushedAuthorizationRequestConverter)   <1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .pushedAuthorizationRequestConverters(pushedAuthorizationRequestConvertersConsumer) <2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .authenticationProvider(authenticationProvider) <3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .authenticationProviders(authenticationProvidersConsumer)   <4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .pushedAuthorizationResponseHandler(pushedAuthorizationResponseHandler) <5> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .errorResponseHandler(errorResponseHandler) <6> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<1> `pushedAuthorizationRequestConverter()`: Adds an `AuthenticationConverter` (_pre-processor_) used when attempting to extract an https://datatracker.ietf.org/doc/html/rfc9126#section-2.1[OAuth2 pushed authorization request] from `HttpServletRequest` to an instance of `OAuth2PushedAuthorizationRequestAuthenticationToken`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<2> `pushedAuthorizationRequestConverters()`: Sets the `Consumer` providing access to the `List` of default and (optionally) added ``AuthenticationConverter``'s allowing the ability to add, remove, or customize a specific `AuthenticationConverter`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<3> `authenticationProvider()`: Adds an `AuthenticationProvider` (_main processor_) used for authenticating the `OAuth2PushedAuthorizationRequestAuthenticationToken`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<4> `authenticationProviders()`: Sets the `Consumer` providing access to the `List` of default and (optionally) added ``AuthenticationProvider``'s allowing the ability to add, remove, or customize a specific `AuthenticationProvider`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<5> `pushedAuthorizationResponseHandler()`: The `AuthenticationSuccessHandler` (_post-processor_) used for handling an "`authenticated`" `OAuth2PushedAuthorizationRequestAuthenticationToken` and returning the https://datatracker.ietf.org/doc/html/rfc9126#section-2.2[OAuth2 pushed authorization response]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<6> `errorResponseHandler()`: The `AuthenticationFailureHandler` (_post-processor_) used for handling an `OAuth2AuthenticationException` and returning the https://datatracker.ietf.org/doc/html/rfc9126#section-2.3[OAuth2Error response]. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestEndpointConfigurer` configures the `OAuth2PushedAuthorizationRequestEndpointFilter` and registers it with the OAuth2 authorization server `SecurityFilterChain` `@Bean`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestEndpointFilter` is the `Filter` that processes OAuth2 pushed authorization requests. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestEndpointFilter` is configured with the following defaults: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `*AuthenticationConverter*` -- A `DelegatingAuthenticationConverter` composed of `OAuth2AuthorizationCodeRequestAuthenticationConverter`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `*AuthenticationManager*` -- An `AuthenticationManager` composed of `OAuth2PushedAuthorizationRequestAuthenticationProvider`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `*AuthenticationSuccessHandler*` -- An internal implementation that handles an "`authenticated`" `OAuth2PushedAuthorizationRequestAuthenticationToken` and returns the OAuth2 pushed authorization response. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* `*AuthenticationFailureHandler*` -- An `OAuth2ErrorAuthenticationFailureHandler`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[[oauth2-pushed-authorization-request-endpoint-customizing-authorization-request-validation]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+=== Customizing Pushed Authorization Request Validation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2AuthorizationCodeRequestAuthenticationValidator` is the default validator used for validating specific OAuth2 pushed authorization request parameters used in the Authorization Code Grant. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The default implementation validates the `redirect_uri` and `scope` parameters. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+If validation fails, an `OAuth2AuthorizationCodeRequestAuthenticationException` is thrown. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2PushedAuthorizationRequestAuthenticationProvider` provides the ability to override the default pushed authorization request validation by supplying a custom authentication validator of type `Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext>` to `setAuthenticationValidator()`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[TIP] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+`OAuth2AuthorizationCodeRequestAuthenticationContext` holds the `OAuth2AuthorizationCodeRequestAuthenticationToken`, which contains the OAuth2 pushed authorization request parameters. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[IMPORTANT] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+If validation fails, the authentication validator *MUST* throw `OAuth2AuthorizationCodeRequestAuthenticationException`. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+A common use case during the development life cycle phase is to allow for `localhost` in the `redirect_uri` parameter. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The following example shows how to configure `OAuth2PushedAuthorizationRequestAuthenticationProvider` with a custom authentication validator that allows for `localhost` in the `redirect_uri` parameter: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,java] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			OAuth2AuthorizationServerConfigurer.authorizationServer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		.with(authorizationServerConfigurer, (authorizationServer) -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			authorizationServer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.pushedAuthorizationRequestEndpoint(pushedAuthorizationRequestEndpoint -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					pushedAuthorizationRequestEndpoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .authenticationProviders(configureAuthenticationValidator()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return http.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+private Consumer<List<AuthenticationProvider>> configureAuthenticationValidator() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return (authenticationProviders) -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authenticationProviders.forEach((authenticationProvider) -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (authenticationProvider instanceof OAuth2PushedAuthorizationRequestAuthenticationProvider) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authenticationValidator = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// Override default redirect_uri validator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new CustomRedirectUriValidator() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						// Reuse default scope validator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						.andThen(OAuth2AuthorizationCodeRequestAuthenticationValidator.DEFAULT_SCOPE_VALIDATOR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				((OAuth2PushedAuthorizationRequestAuthenticationProvider) authenticationProvider) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					.setAuthenticationValidator(authenticationValidator); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static class CustomRedirectUriValidator implements Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void accept(OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			authenticationContext.getAuthentication(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		RegisteredClient registeredClient = authenticationContext.getRegisteredClient(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		String requestedRedirectUri = authorizationCodeRequestAuthentication.getRedirectUri(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// Use exact string matching when comparing client redirect URIs against pre-registered URIs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!registeredClient.getRedirectUris().contains(requestedRedirectUri)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 [[oauth2-device-authorization-endpoint]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 == OAuth2 Device Authorization Endpoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |