My Spring Webflux application provides multiple authentication methods for the APIs, the user either presents a JWT token or he presents a userid and password. I understand that each authentication method is a separate SecurityWebFilterChain. In my security config I defined 2 Beans, one for basic auth and one for JWT. Setting up each one for different endpoints works fine using a SecurityMatcher, but how do I setup both for the same endpoint. I want either basic auth or JWT token to authenticate for a specific endpoint. All my attempts result in the first authentication method failing and returning a 401 unauthorized without attempting to try the second method. How do I get it not to fail but to try the second SecurityWebFilterChain bean?
Here is the code from my security config
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Autowired private SecurityContextRepository securityContextRepository;
@Bean
SecurityWebFilterChain webHttpSecurity(
ServerHttpSecurity http, BasicAuthenticationManager authenticationManager) {
http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/something/**"))
.authenticationManager(authenticationManager)
.authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated())
.httpBasic()
.and()
.csrf()
.disable();
return http.build();
}
@Bean
SecurityWebFilterChain springWebFilterChain(
ServerHttpSecurity http, AuthenticationManager authenticationManager) {
String[] patterns =
new String[] {
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/webjars/**",
};
return http.cors()
.disable()
.exceptionHandling()
.authenticationEntryPoint(
(swe, e) ->
Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED)))
.accessDeniedHandler(
(swe, e) ->
Mono.fromRunnable(() -> swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN)))
.and()
.csrf()
.disable()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers(patterns)
.permitAll()
.pathMatchers(HttpMethod.OPTIONS)
.permitAll()
.anyExchange()
.authenticated()
.and()
.build();
}
The first Bean sets up basic auth for one specific endpoint using a custom authentication manager which veruifies the userid and password, the second bean sets up JWT auth for all other endpoints (with a custom AuthenticationManager that verifies the token etc.) except those that are excluded. Lets say I have the following endpoints
- /api/something
- /api/whatever
- .....
endpoint 1 I want to authenticate with either basic auth or JWT endpoint 2,3 ,n I want only JWT As I have it now endpoint 1 is using only basicAuth and all other endpoints use JWT. How can I add JWT to endpoint 1 as well?