Search code examples
spring-bootspring-securityoauth-2.0jwtauth0

Springboot application do not work with token AUTH0 (error 403)


I have a problem with springboot security. I do not why but the latter do not working with AUTH0 token. Let me start by saying that I'm learning AUTH0 and this is my first demo. In AUTH0 I have created an application and an API with permission read:message. Then I created a user and created the role for this user as 'admin'. I then gave the 'admin' role the 'read:message' permissions of my API and assigned the role to the created user. Finally I authorized the API to the application.

In my springboot app I have created a security config:

@EnableWebSecurity
public class SecurityConfig {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class.getName());

@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();

    http.authorizeRequests()
            .antMatchers("/api/public/**").permitAll()
            .antMatchers("/api/private/**").authenticated()
            .mvcMatchers("/api/private-scoped").hasAuthority("SCOPE_read:message")
            .and()
            .cors()
            .and()
            .oauth2ResourceServer().jwt();

         return http.build();
}
@Bean
JwtDecoder jwtDecoder(){
    NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromIssuerLocation(issuer);

    OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
    OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
    OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
    jwtDecoder.setJwtValidator(withAudience);

    return jwtDecoder;
 }
}

The audience validator:

public class AudienceValidator implements OAuth2TokenValidator<Jwt> {

private final String audience;

public AudienceValidator(String audience){
    this.audience = audience;
}

@Override
public OAuth2TokenValidatorResult validate(Jwt token) {
    OAuth2Error error = new OAuth2Error("invalid_token", "L'audience richiesto è mancante", null);

    if (token.getAudience().contains(audience)) {
        return OAuth2TokenValidatorResult.success();
    }

    return OAuth2TokenValidatorResult.failure(error);
 }
}

And the api controller:

@RestController
@RequestMapping(path = "/api", produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin(origins = "*")
public class APIController {
@GetMapping(value = "/public")
public Message publicEndpoint() {
    return new Message("All good. You DO NOT need to be authenticated to call /api/public.");
}

@GetMapping(value = "/private")
public Message privateEndpoint() {
    return new Message("All good. You can see this because you are Authenticated.");
}

@GetMapping(value = "/private-scoped")
public Message privateScopedEndpoint() {
    return new Message("All good. You can see this because you are Authenticated with a Token granted the 'read:messages' scope");
 }
}

In postman I make the following call to get the token:

curl --location 'https://dev-tkjcpdzq3rhabjp1.us.auth0.com/oauth/token' \
--header 'content-type: application/json' \
--header 'Cookie: did=s%3Av0%3A602acbc0-731c-11ee-b98a-    95a049e9e317.nODjWjq1tEeLZzXXtNkzFz6p88pwZ3hhvtROw5YLWu4; did_compat=s%3Av0%3A602acbc0-731c-11ee-b98a-95a049e9e317.nODjWjq1tEeLZzXXtNkzFz6p88pwZ3hhvtROw5YLWu4' \
--data '{"client_id":"FlzXFNGz3Hr9F54usq8D3Es9lDAVEueR","client_secret":"hZslREfUgifNU4vqIp36Qo3GttLTRWDCC9TsgC0fIgsyyJ27Iq63C-M3M7MUrXr4","audience":"http://myAPI/api","grant_type":"client_credentials"}'

and then I make the following call to my spring boot app:

curl --location 'http://localhost:8080/app/api/private-scoped' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Inl5R0V0MHJseDBjUFVRUXFEc3JXdyJ9.eyJpc3MiOiJodHRwczovL2Rldi10a2pjcGR6cTNyaGFianAxLnVzLmF1dGgwLmNvbS8iLCJzdWIiOiJGbHpYRk5HejNIcjlGNTR1c3E4RDNFczlsREFWRXVlUkBjbGllbnRzIiwiYXVkIjoiaHR0cDovL215QVBJL2FwaSIsImlhdCI6MTY5ODIzOTcyMiwiZXhwIjoxNjk4MzI2MTIyLCJhenAiOiJGbHpYRk5HejNIcjlGNTR1c3E4RDNFczlsREFWRXVlUiIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.ljA4UqAuwdBZzEAxcnc8L7Nzt3HDeTQxEDnQKuPhOFEPaJ_LqDsjQ1SOcpz7_tYNuf7aa_5bX4TernyN5o4iFTkg1ECiv2_OnsdKS8u7kNr0rUB9cofL6xXtaxwl4-ofUxUq_uEBnu7NZaRC7TT6X6PzNGdWd_gPgIzAMRAZa99tsM2DGEPYAbRkLZ7cqGyoDivemJnqMH5LUon-bt0otBp64ta0O45LZ8IIDprHcQ9BusRW5v02evBBANN5LT6GKxo6Y0KrugL04ec2mCRvvz-FW318A9djBAE-Lo1gVPHaB4njsFcHdtcxesHe9ja-qbG2x1ccckPOgTrzIciEhw' \
--header 'Cookie: JSESSIONID=FA60C42C23DC34ECAD41D542EB480383'

but the latter always replies to me with code 403. Where am I going wrong?


Solution

  • I solved the problem rewriting the security class in this way:

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class.getName());
    
    @Value("${auth0.audience}")
    private String apiAudience;
    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuer;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors();
        JwtWebSecurityConfigurer
                .forRS256(apiAudience, issuer)
                .configure(http)
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/api/public").permitAll()
                .antMatchers(HttpMethod.GET, "/api/private").authenticated()
                .antMatchers(HttpMethod.GET, "/api/private-scoped").hasAuthority("read:message");
     }
    
    }
    

    I also deleted the audience class and in the Auth0 settings, in the Machine to Machine tab of my API I checked the permissions checkbox. Now everything works correctly.