Reputation: 463
I have an Azure AD JWT token that is obtained using Msal library but when I try to validate this token something is wrong:
Client: A Sharepoint Web Part
const config = {
auth: {
clientId: "xxxxx",
authority: "https://login.microsoftonline.com/yyyyyy"
}
};
const myMSALObj = new UserAgentApplication(config);
let accessTokenRequest = {
scopes: ["user.read"],
loginHint: this.context.pageContext.user.loginName,
extraQueryParameters: {domain_hint: 'organizations'}
}
myMSALObj.acquireTokenSilent(accessTokenRequest).then(
function(accessTokenResponse) {
// Acquire token silent success
let accessToken = accessTokenResponse.accessToken;
On the other hand I have a server app (Java) where the access token is validated
Validator:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-storage</artifactId>
<version>8.6.2</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.11.0</version>
</dependency>
Code
String token="<your AD token>";
DecodedJWT jwt = JWT.decode(token);
System.out.println(jwt.getKeyId());
JwkProvider provider = null;
Jwk jwk =null;
Algorithm algorithm=null;
try {
provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/common/discovery/keys"));
jwk = provider.get(jwt.getKeyId());
algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algorithm.verify(jwt);// if the token signature is invalid, the
method will throw SignatureVerificationException
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (JwkException e) {
e.printStackTrace();
}catch(SignatureVerificationException e){
System.out.println(e.getMessage());
}
My problem is that when I try to validate this token I obtained this error: The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA
I'm stuck with this, If the token is right, Why I have this error?
Regards
Upvotes: 2
Views: 3031
Reputation: 463
Finally, It works with something like this.
To obtain the token (using adal in the Web Part):
// Obtaining token provider
let tp = await this.context.aadTokenProviderFactory.getTokenProvider();
let config = tp["_defaultConfiguration"];
let aadInstanceUrl = config.aadInstanceUrl[length - 1] === "/" ? config.aadInstanceUrl : config.aadInstanceUrl + "/";
// Config context
let ctx = new AuthenticationContext({
tenant: tenantId,
clientId: clientId,
instance: aadInstanceUrl,
redirectUri: config.redirectUri,
extraQueryParameter: "login_hint=" + encodeURIComponent(loginName),
loadFrameTimeout: 60000
});
// Check user
let cu = ctx.getCachedUser();
console.log("USER", cu, loginName, ctx);
if (cu && cu.userName.toLowerCase() !== loginName.toLowerCase()) {
console.log("Clean user cache");
ctx.clearCache();
}
// Login process
console.log("Login process");
// Obtaining Azure AD Token
let azureADToken = this.acquireToken(ctx, clientId);
To validate the token:
String token = "XXXXXX";
DecodedJWT jwt = JWT.decode(token);
System.out.println(jwt.getKeyId());
JwkProvider provider = null;
Jwk jwk = null;
Algorithm algorithm = null;
try {
provider = new UrlJwkProvider(new URL("https://login.microsoftonline.com/common/discovery/keys"));
jwk = provider.get(jwt.getKeyId());
algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algorithm.verify(jwt);// if the token signature is invalid, the method will throw
// SignatureVerificationException
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (JwkException e) {
e.printStackTrace();
} catch (SignatureVerificationException e) {
System.out.println(e.getMessage());
}
System.out.println("works!");
With this dependencies:
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.10</version>
<type>bundle</type>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
<type>bundle</type>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.10</version>
<type>bundle</type>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- JUNIT -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-storage</artifactId>
<version>8.6.2</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.2</version>
</dependency>
</dependencies>
Upvotes: 2
Reputation: 15639
I noticed that the scope is user.read
which means the token is for Microsoft Graph API.
Please note:
If you're a client getting a token for Graph, assume that it's an encrypted string that you should never look at - sometimes it will be. We use a special token format for Graph that they know how to validate - you shouldn't be looking at access tokens if they're not for you.
You can use this access token to call Microsoft Graph API directly, if the token is wrong, you will get the response from Microsoft API server.
Reference:
Upvotes: 2