Search code examples
springspring-bootoauth-2.0jwt

Spring boot resource server with JWT base64 encoded Failed to authenticate since the JWT was invalid


I'm trying to use spring resource server starter with fusionauth.io. the fusion auth token is working just fine with postman and when I want to decode it in jwt.io I should check the secret base64 option to get the valid JWT.

application.yml:

    spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: http://localhost:9011/oauth2/token

SecurityConfig

    @Configuration
public class SecurityConfig extends ResourceServerConfigurerAdapter {

    @Bean
    public JwtDecoder jwtDecoder(){
        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(
                "http://localhost:9011/oauth2/token").build();

        return jwtDecoder;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests(authz -> authz
                        .antMatchers(HttpMethod.GET, "/user/**").permitAll()
                        .antMatchers(HttpMethod.POST, "/user/**").permitAll()
                        .anyRequest().authenticated()).csrf().disable()
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
    }
}

sample jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE1MDE1YWJiYyJ9.eyJhdWQiOiI1OTM4M2ViZS0zYjEzLTQ0YjktODM2MS0xZGQ0MWIxYzdlNDkiLCJleHAiOjE2MDgwODgwMjksImlhdCI6MTYwODA4NDQyOSwiaXNzIjoiYWNtZS5jb20iLCJzdWIiOiJiZGVhZDg5Yi1iNTQ3LTRlNDEtODJlMi1iMWIzNjkxZjA0Y2YiLCJqdGkiOiI3ZjZlYTgwMC1hZTgwLTQ0NzgtOWNmOC1mNzQ5ZTM3YjRlNzIiLCJhdXRoZW50aWNhdGlvblR5cGUiOiJQQVNTV09SRCIsImVtYWlsIjoidGVzdEBlbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImFwcGxpY2F0aW9uSWQiOiI1OTM4M2ViZS0zYjEzLTQ0YjktODM2MS0xZGQ0MWIxYzdlNDkiLCJyb2xlcyI6WyJ1c2VyIl19.o9Qtj7tbqo_imkpNn0eKsg-Fhbn91yu5no1oVaXogNY

the error im getting:

   2020-12-16 05:37:56.934 DEBUG 26116 --- [nio-8500-exec-3] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2020-12-16 05:37:56.934 DEBUG 26116 --- [nio-8500-exec-3] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2020-12-16 05:38:00.012 DEBUG 26116 --- [nio-8500-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /user/me
2020-12-16 05:38:00.012 DEBUG 26116 --- [nio-8500-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2020-12-16 05:38:00.020 DEBUG 26116 --- [nio-8500-exec-2] o.s.s.o.s.r.a.JwtAuthenticationProvider  : Failed to authenticate since the JWT was invalid
2020-12-16 05:38:00.022 DEBUG 26116 --- [nio-8500-exec-2] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2020-12-16 05:38:00.022 DEBUG 26116 --- [nio-8500-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request

Solution

  • The JwtDecoders.fromIssuerLocation will attempt to resolve the jwks_uri from the OpenID Connect discovery document found using the issuer URI.

    https://github.com/spring-projects/spring-security/blob/848bd448374156020210c329b886fca010a5f710/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoders.java#L119

    The FusionAuth JSON Web Key Set (JWKS) only publishes the public key from asymmetric key pairs. This means there are no public keys published and the Spring boot library cannot verify the token signature.

    For example, if your issuerUri is https://example.com then the OpenID Discovery URL is https://example.com/.well-known/openid-configuration and the value for jwks_uri found in the JSON response from that URL will be https://example.com/.well-known/jwks.json. If you hit that URL you will see no public keys are being returned, this is the JSON that the library is consuming in an attempt to build the public key necessary to validate the JWT signature.

    To use this strategy then you'll need to configure FusionAuth to sign the JWT using an RSA or ECDSA key pair instead of the default HMAC key which is symmetric.

    Generate a new RSA or ECDA key pair in Key Master (Settings > Key Master) and then ensure you have your JWT signing configuration use that key. The primary JWT signing configuration will be found in the tenant, with optional application level overrides.

    https://fusionauth.io/docs/v1/tech/core-concepts/tenants/#jwt https://fusionauth.io/docs/v1/tech/core-concepts/applications/#jwt

    Hope that helps. Once you modify your configuration so that public keys are returned in the JWKS response, and the library is still not validating the token, please re-open and we can go from there.