0

I'm working on some java code and running into an issue. We're hoping to validate JWT tokens issued by Azure AD - in a java application.

This example is working mostly ok, except for the signature verification. Something must be missing, but I'm not able to see what that might be.

--

fetching test tokens

import adal
import requests
import pprint

# Bas snowflake test
tenant_id = "tenant-id-12312-123-123-123"
client_id = "valid-client-id-123-123-123"

resource = "https://graph.microsoft.com"  # the resource you want to access

# Create an instance of ADAL authentication context
authority_url = "https://login.microsoftonline.com/" + tenant_id
context = adal.AuthenticationContext(authority_url)

# Obtain an authorization code with the user's credentials
authorization_code = context.acquire_user_code(resource, client_id)

# Print the message and ask the user to perform 2FA verification
print(authorization_code['message'])

# Ok
token = context.acquire_token_with_device_code(resource, authorization_code, client_id)

pprint.pprint(token)

pom.xml

    <dependency>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>azure-storage</artifactId>
        <version>8.6.6</version>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>4.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>jwks-rsa</artifactId>
        <version>0.22.0</version>
    </dependency>

implementation

    boolean validated = false;
    try {
        log.info(String.format("tokenBody.token: %s", tokenBody.token));
        DecodedJWT jwt = JWT.decode(tokenBody.token);
        log.info(String.format("jwt.getKeyId(): %s", jwt.getKeyId()));
        JwkProvider provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/tenant-id-12312-123-123-123/discovery/v2.0/keys"));
        Jwk jwk = provider.get(jwt.getKeyId());
        log.info(String.format("jwk.getPublicKey(): %s", jwk.getPublicKey()));
        Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);

        List<Algorithm> algorithms = List.of(
                Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null),
                Algorithm.RSA512((RSAPublicKey) jwk.getPublicKey(), null),
                Algorithm.RSA384((RSAPublicKey) jwk.getPublicKey(), null),
                Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey()),
                Algorithm.RSA512((RSAPublicKey) jwk.getPublicKey()),
                Algorithm.RSA384((RSAPublicKey) jwk.getPublicKey())
        );

        algorithms.forEach(a -> {
            try {
                log.info("Verifying JWT ...");
                a.verify(jwt);
                log.info("JWT verified!");
            } catch (Exception ignored) {
                log.info("JWT verification failed");
            } finally {
                log.info("----");
            }
        });


        log.info(String.format("jwt.getSignature(): %s", jwt.getSignature()));
        algorithm.verify(jwt);
        validated = true;
    } catch (MalformedURLException e) {
        log.error("malformed url exception", e);
    } catch (JwkException e) {
        log.error("jwk exception", e);
    } catch (SignatureVerificationException e) {
        log.error("signature verification", e);
    } catch (Exception e) {
        log.error("other error", e);
    }

but keep seeing

signature verification
com.auth0.jwt.exceptions.SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA
Bas Kuis
  • 748
  • 1
  • 7
  • 20

1 Answers1

1

Note that: The access token generated for Microsoft Graph API cannot be validated as the token is not meant for the application.

I created an Azure AD Application and generated auth code using below endpoint:

https://login.microsoftonline.com/TenantID/oauth2/authorize?
&client_id=ClientID
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=12345

enter image description here

Now, I generated access token using below parameters:

https://login.microsoftonline.com/TenantID/oauth2/v2.0/token

client_id:ClientID
grant_type:authorization_code
scope:https://graph.microsoft.com/.default
code:code
redirect_uri:https://jwt.ms
client_secret:ClientSecret

enter image description here

When I decoded the access token, I got the same error like below:

The aud is https://graph.microsoft.com and using RSA256 algorithm

enter image description here

enter image description here

To resolve the error, try the below:

In the Azure AD Application Expose an API and add the scope:

enter image description here

Grant the admin consent by adding the scope in API permissions:

enter image description here

Note that: Make use of the scope api://ClientID/access_as_user to resolve the issue.

I generated auth-code using below endpoint:

https://login.microsoftonline.com/TenantID/oauth2/authorize?
&client_id=ClientID
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=api://ClientID/access_as_user
&state=12345

enter image description here

I generated the access token by using scope as api://ClientID/access_as_user like below:

enter image description here

When I decoded the above access token, Signature Verified successfully like below:

enter image description here

References:

spring security - Verify Signature with Azure AD - Stack Overflow by junnas

java - Validation of Azure AD token signature is invalid - Stack Overflow by Carl Zhao

Rukmini
  • 6,015
  • 2
  • 4
  • 14
  • Thanks for your very detailed answer! I'm still a bit unclear on why tokens issued for graph would not be able to be validated by the https://login.microsoftonline.com/xxx/discovery/v2.0/keys – Bas Kuis Apr 14 '23 at 16:04
  • 1
    This is answer helped me out, so thanks a lot! – Bas Kuis Apr 14 '23 at 16:25