'Spring Boot security JWT hasAuthority not work properly
I secure our Spring Boot API with Auth0 and JWT.
When I decode JWT the result is:
{
"iss": "https://****.auth0.com/",
"sub": "auth0|62483c747a2519006fd75914",
"aud": [
"https://***.com/",
"https://***.com/userinfo"
],
"iat": 1648903665,
"exp": 1648990065,
"azp": "ufoZPRxuRqAeulM5u7R5RdlddXvPnOTn",
"scope": "openid profile email",
"permissions": [
"read:brands"
]
}
In the permission array there is read:brands. But when I try to limit API it's not working and returns 403 status for GET /admin/v1/brands.
Here is security config:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui/**",
"/webjars/**",
"/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html"
);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.antMatchers(HttpMethod.GET, "/admin/v1/brands").hasAuthority("read:brands")
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.decoder(jwtDecoder());
}
JwtDecoder jwtDecoder() {
OAuth2TokenValidator<Jwt> withAudience = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(withAudience, withIssuer);
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
jwtDecoder.setJwtValidator(validator);
return jwtDecoder;
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
var config = new CorsConfiguration().applyPermitDefaultValues();
config.setAllowedMethods(List.of(
HttpMethod.GET.name(),
HttpMethod.PUT.name(),
HttpMethod.POST.name(),
HttpMethod.DELETE.name()
));
source.registerCorsConfiguration("/**", config);
return source;
}
}
Solution 1:[1]
Found it!
I had to add jwtAuthenticationConverter
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
public static final String AUTHORITIES_CLAIM_NAME = "permissions";
@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui/**",
"/webjars/**",
"/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html"
);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers(
"/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html"
)
.permitAll()
.antMatchers(HttpMethod.GET, "/admin/v1/brands")
.hasAuthority("read:brands")
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(authenticationConverter())
.decoder(jwtDecoder());
}
JwtDecoder jwtDecoder() {
OAuth2TokenValidator<Jwt> withAudience = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(withAudience, withIssuer);
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
jwtDecoder.setJwtValidator(validator);
return jwtDecoder;
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
var config = new CorsConfiguration().applyPermitDefaultValues();
config.setAllowedMethods(List.of(
HttpMethod.GET.name(),
HttpMethod.PUT.name(),
HttpMethod.POST.name(),
HttpMethod.DELETE.name()
));
source.registerCorsConfiguration("/**", config);
return source;
}
protected JwtAuthenticationConverter authenticationConverter() {
JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
authoritiesConverter.setAuthorityPrefix("");
authoritiesConverter.setAuthoritiesClaimName(AUTHORITIES_CLAIM_NAME);
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
return converter;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Pooya Saberian |
