Expected Behavior
when this is used:
@Bean
SecurityFilterChain configure(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> authz)
throws Exception {
http.oauth2ResourceServer(c -> c.jwt(Customizer.withDefaults()));
and a invalid JWT is used to access any Rest Endpoints, I would expect that spring framework returns RFC 9457 error details, or at least make it somehow configurable to do so.
Current Behavior
it returns an empty body and some 4xx error status.
Context - What other alternatives have you considered?
I tried some ideas using :
SecurityFilterChain configure(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> authz)
throws Exception {
http.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler())
)
.exceptionHandling(exceptionHandling -> exceptionHandling
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
);
and
@Slf4j
@RestControllerAdvice
public final class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(JwtException.class)
public ProblemDetail handleJwtException(JwtException ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, ex.getMessage());
problemDetail.setTitle("Unauthorized");
problemDetail.setType(URI.create("https://example.com/unauthorized"));
return problemDetail;
}
but was never able to catch the JWTException in order to put RFC 9457 error details into the response body .
-
What are you trying to accomplish? comply with https://www.rfc-editor.org/rfc/rfc9457.html
-
Are you aware of any workarounds? yes , but with no success.
Comment From: bodote
what I don't understand is why the HttpSecurity..oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()).authenticationEntryPoint(..) does not catch any Exception thrown by the JwtDecoder when the latter comes across an unvalid JWT.
The workaround I found so far, is to add a custom filter before the UsernamePasswordAuthenticationFilter http.addFilterBefore(new AuthenticationServiceExceptionFilter(), UsernamePasswordAuthenticationFilter.class) and catch the AuthenticationServiceException there. But is there no other way ? And what is the HttpSecurity..oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()).authenticationEntryPoint(..) good for anyway, if it seems not to catch any errors in JWT processing ?
BTW: using Spring Boot 3.2.5
Comment From: ahmd-nabil
(I am not an expert and you should wait for an expert to answer more thoroughly)
1. authenticationEntryPoint(..) does handle authorization errors by fetching error data and attaching them to WWW-Authenticate header complying with RFC 6750.
2. @RestControllerAdvice doesn't catch spring security exception, that is because spring security filters happen before the request even reaches the dispatcher servlet (or controllers) more about that here spring-security-docs
if you need different behavior, my suggestion would be either keep your customExceptionHandlingFilter which is fine. or override AuthenticationEntryPoint.
.authenticationEntryPoint(new YourCustomAuthenticationEntryPoint())
Comment From: Toerktumlare
AuthenticationServiceException as the docs states is an exception that is thrown if your service takes the responsibility for not being able to process the request. For instance a sub service is not available, or a processing error has occurred.
AuthenticationEntryPoint is called in the ExceptionTranslationFilter when either a AccessDeniedException or AuthenticationException is thrown, or any subclass of them, or a wrapped such exception. This in turn semantically means that the service does not take responsibility and instead claims that the client has done something wrong security wise and will then for instance reroute them to a place where they can authenticate or elevate themselves. So basically the request was correct, but the client was not allowed to do what they asked for.
Providing a poorly formatted JWT isnt a security exception but more of a formatting/validation question, which means the client did something wrong and the exception should not be caught in the ExceptionTranslationFilter as the code current stands and as it does currently return a 4xx error telling the client that they did something wrong. Which they did.
Comment From: devshrm
This fixed this issue for me : ~~ @patkovskyi, thanks for reaching out. Please instead specify the entry point directly to the authentication mechanism, like so:
http
.authorizeRequests()
// ...
.oauth2ResourceServer()
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
.jwt()
// ...
This will automatically configure exceptionHandling() to use your CustomAuthenticationEntryPoint as well.
Originally posted by @jzheaux in https://github.com/spring-projects/spring-security/issues/8961#issuecomment-693705813
~~