skip to Main Content

Note: The values that used in this question are only sample. E.g.: 3d355765-XXX-47cd-9c7a-bf31179f5XXX

Hello everyone, I have a ReactJS application and a Spring backend application. However, Backend Application cannot verify token and it throws "The Token’s Signature resulted invalid when verified using the Algorithm: SHA256withRSA" exception.

Could you please help me to find the reason?

Azure Entra Configuration

In Azure Entra, I only configured this "Authentication" configuration for ReactJS application:
enter image description here

ReactJS Configuration

ReactJS application successfully can get access token from Azure OIDC.

react-oidc-context library is used.

Here is ReactJS configuration:

enter image description here

enter image description here

Spring Backend Configuration With Auth0 Library

I use access_token in header with "Bearer" prefix when I send request to backend application. An example: "Bearer eyJ0eXAiOiJKV1QiL….". I can handle that access token. The problem is that I cannot verify it with the publicKey that is obtained from JWK URL.

Libraries

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.8.3</version>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>jwks-rsa</artifactId>
        <version>0.22.1</version>
    </dependency>

Implementation

DecodedJWT jwt = JWT.decode(token);
JwkProvider provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/3d355765-XXX-47cd-9c7a-bf31179f5XXX/discovery/v2.0/keys?appid=5b20cc33-a01b-XXX-be31-cd9ff3aa7XXX"));
Jwk jwk = provider.get(jwt.getKeyId());
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algorithm.verify(jwt);

Library creates this public key:

  Sun RSA public key, 2048 bits
  params: null
  modulus: 26737083189757907003055921442770314338988917140860165426744103322405302728616784576359656902377694864963514916366447987755596040063091127319443429395704125552922128507194605677562878395533638591796237899749004909932248262554836300040575758977279732502744063204426839357267389987189285837088487291113549843075686248327277545438158623612248961469127033882959503541559213717818450130719611600764540097268466124320654392000567544359397082999966622432696244505348004947998457969327542701030616111112222267178710534245286750373749139781560960689184289029103448294950355123548539876783713876691492097395497625781588902647221
  public exponent: 65537

Backend application throws this error at algorithm.verify(jwt); step:

enter image description here

I still don’t understand what is missing.

Do you think is there some missing configuration in Azure Entra, ReactJS application or Spring Backend application?


Additional Information

When I use jsonwebtoken library insed of auth0 library:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
</dependency>

I implemented backend application like this:

Jwts.parserBuilder()
        .setSigningKeyResolver(new SigningKeyResolverAdapter() {
        @Override
        public Key resolveSigningKey(io.jsonwebtoken.JwsHeader header, Claims claims) {
            String jwksUrl = "https://login.microsoftonline.com/3d355765-XXX-47cd-9c7a-bf31179f5XXX/discovery/v2.0/keys?appid=5b20cc33-a01b-XXX-be31-cd9ff3aa7XXX";
            String kid = header.getKeyId();
            log.info("kid value: {}", kid);
            try {
                String jwksJson = JWKSFetcher.getJWKS(jwksUrl);
                log.info("jwksJson value: {}", jwksJson);
                return PublicKeyExtractor.getPublicKeyFromJWKS(jwksJson, kid);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
          }
      })
       .build()
       .parseClaimsJws(token)
       .getBody();

The jsonwebtoken library throws this exception:

JWT signature does not match locally computed signature. JWT validity
cannot be asserted and should not be trusted.



AN UPDATE: "ISSUER IS DIFFERENCES" (06.08.2024)

Today, I noticed there is issuer differences. Could it be a cause of the my problem?

I obtained the token from https://login.microsoftonline.com/{{MY_TENANT_ID}}/v2.0

The issuer in the token that comes back is https://sts.windows.net//{{MY_TENANT_ID}}/ which doesn’t match.

When I check the config at .well-known/openid-configuration the issuer is as expected https://login.microsoftonline.com/{{MY_TENANT_ID}}//v2.0

And also, JWKS endpoint returns this issuer: https://login.microsoftonline.com/{{MY_TENANT_ID}}//v2.0

I updated manifest file:

enter image description here

But, unfortunately I still get token with v1.0:

enter image description here



AN UPDATE: "Cannot Verify Access_Token but Id_Token Works" (09.08.2024)

I know that it shouldn’t be and it is strange but, while the backend application cannot verify access_token and getting ‘Signature verification failed" exception, in the other hand, it can verify the id_token.

2

Answers


  1. Note that, open_id and offline_access are Microsoft Graph scopes which generates token with aud as 00000003-0000-0000-c000-000000000000 that gives "Invalid Signature" error when you validate it.

    To resolve that, you need to expose API by creating custom scopes and generate token with those custom scopes.

    For sample, I exposed an API in an app registration and created custom scopes in it as below:

    enter image description here

    Make sure to change "requestedAccessTokenVersion" to 2 in App’s Manifest for generating access token of version 2.0 :

    enter image description here

    Now, I added these API permissions and granted consent in application from which token will be generated like this:

    enter image description here

    Initially, I ran below authorization request in browser and got code value in address bar after successful authentication:

    https://login.microsoftonline.com/tenantId/oauth2/v2.0/authorize?
    client_id=pkceappId
    &response_type=code
    &redirect_uri=https://jwt.ms
    &response_mode=query
    &scope=api://customApiAppId/test.read api://customApiAppId/test.write
    &state=12345
    &code_challenge=xxxxxxxx
    &code_challenge_method=S256
    

    enter image description here

    Later, I generated access token using authorization code with PKCE flow via Postman like this:

    POST https://login.microsoftonline.com/tenantId/oauth2/v2.0/token
    
    grant_type:authorization_code
    client_id:pkceappId
    scope: api://customApiAppId/test.read api://customApiAppId/test.write
    code:code
    redirect_uri: https://jwt.ms
    code_verifier:S256
    

    Response:

    enter image description here

    When I decoded this token in jwt.io, signature verified successfully and token generated with version 2.0 as below:

    enter image description here
    enter image description here

    In your case, expose an API by creating new custom scope and use those new custom scope values in ssoScopes parameter while generating the access token.

    Make sure not to pass Microsoft Graph scopes like openid or offline_access in ssoScopes parameter.

    Reference:

    java – Azure OAuth2: can’t validate access token – Stack Overflow by me

    Login or Signup to reply.
  2. I found a blog that helped me understand this issue. Please check the problem part https://xsreality.medium.com/making-azure-ad-oidc-compliant-5734b70c43ff

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search