I would like to use Azure AD B2C but have several difficulties using it. One problem I have is to validate the signature of the token. First I wanted to validate the token "manually" using jwt.io.
According to the Microsoft Docs, validating the signature should work like this:
Your app can use the kid claim in the JWT header to select the public key in the JSON document that is used to sign a particular token. It can then perform signature validation by using the correct public key and the indicated algorithm.
My understandig: Grab the kid value out of the header, lookup the key in the metadata under the location of jwks_uri, (assumption) use the value of "n" to verify the signature.
But Jwt.io, jsonwebtoken.io, and jose-jwt all say, that the siganture is invalid.
What am I missing?
You can validate your tokens locally by parsing the token, verifying the token signature, and validating the claims that are stored in the token. Parse the tokens. The JSON Web Token (JWT) is a standard way of securely passing information. It consists of three main parts: Header, Payload, and Signature.
The used key is typically identified by the "kid" (key ID) header parameter. JWT claims check -- The JWT claims set is validated, for example to ensure the token is not expired and matches the expected issuer, audience and other claims.
By default, access tokens are valid for one hour, when they expire the client is redirected to Azure AD to refresh them.
Jwt.io seems to only support HS265 with a string secret and RS256 with a string secret or a certificate.
Azure AD B2C uses the more native form of RS256 which as per RFC 3447, section 3.1 defines that the public key consists of two components: n
and e
. The JWK contains both n
and e
which can be used to generate public key and validate the token signature.
In order to use Jwt.io, you'll need to convert Azure AD B2C's n + e format for the key to a cert format. See this example for a reference on how to do this: Go Language Convert Modulus exponent to X.509 certificate
There is now a way to validate tokens using two npm packages.
The information was made available at: Microsoft - Example-verifying-validation-tokens
The example below was modified from example in Microsoft - Example-verifying-validation-tokens
import jwt from 'jsonwebtoken';
import jkwsClient from 'jwks-rsa';
// Variables that need to be defined based on your Azure B2C Configuration.
const jwksUri = 'https://MY-B2C-TENANT.b2clogin.com/MY-B2C-TENANT.onmicrosoft.com/MY-USER-FLOW-NAME/discovery/v2.0/keys';
const client = jkwsClient({
jwksUri
});
export function getKey(header, callback) {
client.getSigningKey(header.kid, (err, key) => {
var signingKey = key.getPublicKey();
callback(null, signingKey);
});
}
export function isTokenValid(token, applicationId, issuerUri) {
return new Promise((resolve) => {
const options = {
audience: [applicationId],
issuer: [issuerUri]
};
jwt.verify(token, getKey, options, (err, decoded) => {
if (err) {
// eslint-disable-next-line no-console
console.error('Jwt Validation Failed', err);
resolve(false);
} else {
// eslint-disable-next-line no-console
console.debug(decoded)
resolve(true);
}
});
});
}
const applicationId = 'APPLICATION ID OF B2C TENANT'
const issuerUri = 'In the User Flow Properties'
const valid = isTokenValid('some token value without "Bearer", applicationId, issuerUri);
jwksUri
contains the user "User Policy". If you have multiple "User Policies", you will need to figure out how to instantiate the jkwsClient
with correct jwksUri
based on the each "User Policy" flow.'e3R5cDogIkpXVCIsIGFsZzogIlJTMjU2Iiwga2lkOiAiWU9VX1NORUFLWV9SQUJCSVQifQ==.e2V4cDogMTU5NjYwMTc4NiwgbmJmOiAxNTk2NTk4MTg2LCB2ZXI6ICIxLjAiLCBpc3M6ICJodHRwczovL3doaXRlLXJhYmJpdC5iMmNsb2dpbi5jb20vZjIzNDZhMzBhLTk1ODEtNGU0ZC04MWQwLWQyZjk4NTQ3MWJhOS92Mi4wLyIsIHN1YjogImYzMmNjNmJhLWE5MTctNGE1Ni1hYjhmLWIyNGZmMTg1ODUyOCIsICIuLi4iOiAibW9yZSB2YWx1ZXMuLi4ifQ==.UNODECODEME'.split('.').map((value, index) => {
// The signature can't be decoded
if(index > 1) { return value; }
return atob(value);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With