Reputation: 5781
We're moving an app from "Sign-In with Google" to "Sign-In with Microsoft". It is an SPA, but queries an API for data. The client-side is all working using MSAL v2 (msal-browser.min.js), and we can sign in and out just fine.
When we send requests to the server, we send the JWT ID token. The server is a NodeJS API.
I can't see any Microsoft server-side Node library that has a 'verify' method we can use to validate the ID token from the client.
We've been looking at @azure/msal-node
and @azure/msal-common
, but can't see anything that we can feed the ID token to, to verify that the token is valid, and that the user is logged in.
We want to return 'unauthorised' from the API if the user is not logged in.
With Google, this was easy, we used google-auth-library
like this:
const client = new OAuth2Client(googleClientId)
const ticket = await client.verifyIdToken({ idToken: googleIdToken, audience: googleClientId })
const payload = ticket.getPayload() // jwt payload
I hope the Microsoft equivalent is just hard to find, or it's not and I'm just being silly in not finding it.
Is there a Node library that provides a way to verify an MSAL ID token, which confirms the token is valid and that the user is signed in...?
Upvotes: 16
Views: 14087
Reputation: 41
Update to show how we now validate tokens after moving from azure-ad_jwt_v2 using jwks-rsa and jsonwebtoken.
const client = jwksClient({
jwksUri: `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}/discovery/v2.0/keys`,
});
function getKey(header, callback) {
client.getSigningKey(header.kid, (err, key) => {
if (err) {
return callback(err);
}
const signingKey = key.getPublicKey();
callback(null, signingKey);
});
}
export async function verifyToken(token: string, callback: (err, token?: AccessToken) => void) {
jwt.verify(token, getKey, { algorithms: ["RS256"] }, (err, decoded) => {
if (err) {
return callback(err, null);
}
const token = decoded as AccessToken;
// Verify claims
function confirmScope() {
return token.scp === process.env.AZURE_FRONT_END_SCOPE;
}
function confirmTenant() {
return token.tid === process.env.AZURE_TENANT_ID;
}
function confirmAudience() {
return token.azp === process.env.AZURE_FRONT_END_APP_ID;
}
function confirmExpiration() {
// the EXP property on a token is defined in seconds, whereas Date.now() returns milliseconds
return token.exp * 1000 > Date.now();
}
const tokenIsValid =
confirmAudience() &&
confirmScope() &&
confirmTenant() &&
confirmExpiration();
if (!tokenIsValid) {
return callback(new Error("Invalid token"));
}
callback(null, token);
});
}
Essentially the public keys for your azure tenant are accessible by anyone. The access tokens can be decoded by anyone using the public keys.
However - nobody can fraudulently create a token that would then be successfully be decoded by this public key because they lack the private signing key that lives on the azure servers.
So - get public keys, decode access token, confirm specific tenant information, good to go!
Sorry for the late response.
Upvotes: 2
Reputation: 135
I had a similar issue and found this library. It was published 2 months ago according to Npmjs.
Edit:
In response to comments, for this package to consider a msal token as valid, it does the following :
Verify if all required props are passed in.
Decode the token using the jsonwebtoken library.
Send a request to https://login.microsoftonline.com/{tenantId}/discovery/keys?appid={applicationId} to receive all public keys unique to your applicationId and tenantId. This action is cached after one successful attempt.
Verify all required access token claims: aud, tid,iss,scp, appid, exp.
If the comparison succeeds, the token is valid.
This and more info on what the package does to validate an Azure AD Token can be found here
Please note that validate means that all the prvious steps have been successful
Upvotes: -2
Reputation: 836
MSAL Node is for acquiring tokens so clients can access protected resources, not for validating tokens in your API. I don't think Microsoft currently provides any Node libraries for validating tokens, but you can use jsonwebtoken instead.
There is a code sample in the MSAL Node library that shows how to validate certain claims in tokens.
If you are curious what the steps to validate an Azure AD JWT are in more detail, I wrote an article that walks through the various steps. The code sample is written in Java, but all of the steps are applicable to Node as well.
Upvotes: 12