I’m working on a project that does authentication based on JWT. Until now I was able to hit my token API and authorize other APIs with it. Strangely today I’m not able to hit any request at all! I get a 401 Unauthorised on all of them, but no authentication happens in the first place. On some debugging, I saw I was getting a ROLE_ANONYMOUS
authority from one of the default filters.
After disabling that, I get, Authentication Object was not found in the SecurityContext
error. Then I saw that the deferredContext
supplier in SecurityContextHolderFilter
returns null. I have no clue on how to proceed, any help would be appreciated.
Here’s my SecurityConfig file, I’m fairly new to spring, so please bear with me.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final VineryUserDetailsService vineryUserDetailsService;
private RSAKey rsaKey;
public SecurityConfig(@Lazy VineryUserDetailsService vineryUserDetailsService) {
this.vineryUserDetailsService = vineryUserDetailsService;
}
@Bean
public AuthenticationManager authManager(UserDetailsService userDetailsService) {
var authProvider = new DaoAuthenticationProvider();
authProvider.setAuthoritiesMapper(new RoleHierarchyAuthoritiesMapper(roleHierarchy()));
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(authProvider);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.anonymous(AbstractHttpConfigurer::disable)
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorizeHttpRequests ->
authorizeHttpRequests
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.requestMatchers(ant(SIGNUP), ant(LOGIN)).permitAll()
.requestMatchers(ant(ADMIN_TEST)).hasAuthority("SCOPE_ROLE_ADMIN")
.requestMatchers(ant(USER)).hasAuthority("SCOPE_ROLE_USER")
.anyRequest().authenticated()
)
.userDetailsService(vineryUserDetailsService)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()))
.build();
}
public AntPathRequestMatcher ant(String pattern) {
return new AntPathRequestMatcher(pattern);
}
@Bean
public DefaultWebSecurityExpressionHandler customWebSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy());
return expressionHandler;
}
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
// String hierarchy = "ROLE_ADMIN > ROLE_STAFF n ROLE_STAFF > ROLE_USER";
String hierarchy = "ROLE_ADMIN > ROLE_USER";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
JwtEncoder jwtEncoder(JWKSource<SecurityContext> jwks) {
return new NimbusJwtEncoder(jwks);
}
@Bean
JwtDecoder jwtDecoder() throws JOSEException {
return NimbusJwtDecoder.withPublicKey(rsaKey.toRSAPublicKey()).build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:5173"));
configuration.setAllowedMethods(List.of("GET", "POST"));
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Here’s the filter chain