JWT Token Validation on Spring Boot gives Failed Parse Token

I have been trying and testing out Okta as an Identity provider for Login and communication across bunch of Microservices.
Wanted to integrate Token Validation and Claims Decoding at Spring Cloud API Gateway Filters.

As part of this work,

  1. Authentication and Token Fetch, I am doing from Postman, running bunch of APIs getting sessionToken, then Code and then ID and Access Token (by PKCE). All good so far.

  2. Next, My API calls to microservices are routed through API gateway and I am sending Access token as part of each API’s header and interceptor/filers try to decode the Token. Find the error there:

‘’’
com.okta.jwt.JwtVerificationException: Failed to parse token
at com.okta.jwt.impl.jjwt.TokenVerifierSupport.decode(TokenVerifierSupport.java:87)
at com.okta.jwt.impl.jjwt.JjwtAccessTokenVerifier.decode(JjwtAccessTokenVerifier.java:56)

Caused by: io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:399)
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:529)
at io.jsonwebtoken.impl.ImmutableJwtParser.parse(ImmutableJwtParser.java:153)
at com.okta.jwt.impl.jjwt.TokenVerifierSupport.decode(TokenVerifierSupport.java:81)
… 103 more
‘’’

I followed Validate Access Tokens | Okta Developer link .
I am not sure what the missing piece could be.

Cross checked:

  1. Issuer
  2. Audience
    For Authorization Server I tried using default one, but created a new Auth Server, but the issue persists.
  3. Since I used OIDC + SPA for Application, I only got ClientID without any Client Secret.
    So, I cannot use remote /introspect API option because client secret is mandatory in that case.

I am in a no hope zone right now :slight_smile: Need some help.

Do you want to share a code snippet which does validation call?

Hi @phi1ipp I am using the regular code snippet provided by Okta as part of local validation of access token ( link in the above post ).

AccessTokenVerifier jwtVerifier = JwtVerifiers.accessTokenVerifierBuilder()
.setIssuer(“https://${yourOktaDomain}/oauth2/default”)
.setAudience(“api://default”) // defaults to ‘api://default’
.setConnectionTimeout(Duration.ofSeconds(1)) // defaults to 1s
.setReadTimeout(Duration.ofSeconds(1)) // defaults to 1s
.build();

Jwt jwt = jwtVerifier.decode(jwtString)

If you are using custom authZ server then it’s wrong, as custom authZ server definitely uses different issuer URL and audience. Check those out on authZ server page in Okta Admin UI

Hmm, I tried custom Auth Server and audience from the Spring Boot Filter and it was NOT WORKING (same error as above).
But interestingly I ran this simple main with the same token, custom issuer and custom audience and it WORKS just fine and give me claims.


 public static void main(String[] args) {
        String access_token = "eyJrxyz";
        AccessTokenVerifier jwtVerifier = JwtVerifiers.accessTokenVerifierBuilder()
                .setIssuer("https://{OktaDomain}/oauth2/xyz")
                .setAudience("api://abc")                // defaults to 'api://default'
                .setConnectionTimeout(Duration.ofSeconds(4)) // defaults to 1s
                .build();

        try {
            Jwt jwt = jwtVerifier.decode(access_token);
            System.out.println(jwt.getClaims()+ " "+ jwt.getTokenValue());

        } catch (JwtVerificationException e) {
            e.printStackTrace();
        }

    }

Again, the api-gateway filter logging and other skeleton looks just fine.

As a follow-on I tried forwarding token to the Spring Boot rest endpoint (from api-gateway) and this jwt verifier code works good at the endpoint.
This doesn’t make any sense to me.

My Spring Cloud API Gateway filter looks like this

public class AuthFilter implements GatewayFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            String token = exchange.getRequest().getHeaders().get("Authorization").toString();
           AccessTokenVerifier jwtVerifier = JwtVerifiers.accessTokenVerifierBuilder()
                .setIssuer("https://{OktaDomain}/oauth2/xyz")
                .setAudience("api://abc")                // defaults to 'api://default'
                .setConnectionTimeout(Duration.ofSeconds(4)) // defaults to 1s
                .build();
            Jwt jwt = jwtVerifier.decode(token);
            System.out.println(jwt.getClaims()+ " "+ jwt.getTokenValue());

        } catch (JwtVerificationException e) {
            e.printStackTrace();
        }
        return chain.filter(exchange);
    }
}

So, at last found that there were spring boot and okta compatibility issues.
What worked for me was

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
</parent>

<java.version>11</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
<okta-jwt.version>0.5.7</okta-jwt.version>

<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
<version>2.1.6</version>
</dependency>

Found compatibility versions at GitHub - okta/okta-spring-boot: Okta Spring Boot Starter
Found OAuth 2.0 Patterns with Spring Cloud Gateway | Okta Developer very helpful, helps one avoid writing much of boiler plate code.

Thanks @phi1ipp for your reply.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.