I have created two custom filters, one responsible for validating JWT and one for handling ExpiredJwtException.
I have found solution to invoke them in the right order there: Multiple Spring Security filters, so that the ExpiredJwtException is properly caught:
http.antMatcher("jwtRequestFilter/exceptionHandlerFilter/**")
.addFilterBefore(exceptionHandlerFilter, FilterSecurityInterceptor.class)
.antMatcher("jwtRequestFilter/**")
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
After some refactoring it turned out that all I need to make it work is:
http.antMatcher("jwtRequestFilter/**")
.addFilterBefore(exceptionHandlerFilter, FilterSecurityInterceptor.class)
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
But I don't get how does the antMatcher method work here. Either antMatcher("jwtRequestFilter/exceptionHandlerFilter/**") or antMatcher("jwtRequestFilter/**") is needed to remain correct order.
How does expressions in antMatcher work? Does ** means other filters in the chain and jwtRequestFilter on the beginning of the expression means it is last filter?