Last active
November 24, 2022 05:59
-
-
Save jeff-auth0/13f9643abb9a473635dba48965bb9075 to your computer and use it in GitHub Desktop.
This login script will be used to generate auth0 tokens in return of AAD id_token generated for user logged in to their Windows 10 devices.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Purpose of this script: | |
* This login script will be used to generate auth0 tokens in return of AAD id_token generated | |
* for user logged in to their Windows 10 devices. | |
* | |
* Why: | |
* This is similar to native SIWA, that a desktop windows application performs API based request to OS | |
* to authenticate current user, user sees a consent page, and after consent, application receives | |
* id_token of current user’s Azure AD account associated with Windows 11 machine. | |
* | |
* | |
* @param {string} email - Email of the user | |
* @param {string} password - Microsoft azure ad id_token | |
*/ | |
function login(email, token, callback) { | |
const jwksClient = require("jwks-rsa"); | |
const jwt = require("jsonwebtoken"); | |
const validator = require("validator"); | |
// Key set is cached for 24 hours | |
// as per https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens | |
global.cache = global.cache || {}; | |
global.cache.utiCache = global.cache.utiCache || []; | |
const options = { | |
audience: configuration.client_id, | |
issuer: | |
"https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0", | |
algorithms: ["RS256"], | |
}; | |
const getKey = (token, callback) => { | |
// get the decoded payload and header | |
var decoded = jwt.decode(token, { complete: true }); | |
try { | |
const currentTime = new Date().getTime(); | |
const kid = decoded.header.kid; | |
if ( | |
global.cache.jwks && | |
global.cache.jwks.kid === kid && | |
global.cache.jwks.exp > currentTime | |
) { | |
return callback(null, global.cache.jwks.signingKey); | |
} else { | |
const client = jwksClient({ | |
jwksUri: `https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/discovery/v2.0/keys`, | |
}); | |
client.getSigningKey(kid, function (err, key) { | |
var signingKey = key.publicKey || key.rsaPublicKey; | |
global.cache.jwks = { | |
signingKey: signingKey, | |
exp: currentTime + 60 * 60 * 24 * 1000, // Key expires in 24 hours | |
kid, | |
}; | |
return callback(null, signingKey); | |
}); | |
} | |
} catch (e) { | |
throw new Error(e.message); | |
} | |
}; | |
function checkJwtReuse(decodedToken) { | |
if (!decodedToken.uti) { | |
return callback( | |
new Error( | |
`This token does not have valid uti claim. Refresh your id_token from aad.`, | |
), | |
); | |
} | |
if (global.cache.utiCache.indexOf(decodedToken.uti) === -1) { | |
global.cache.utiCache.push(decodedToken.uti); | |
return; | |
} | |
// If decodedToken.uti is not present OR global.cache.utiCache.indexOf(decodedToken.uti) !== -1 | |
return callback( | |
new Error( | |
`This token was previously used with uti claim: ${decodedToken.uti}. Refresh your id_token from aad`, | |
), | |
); | |
} | |
getKey(token, (error, key) => { | |
if (error) { | |
return callback(new Error(`Unable to get the key. Error: ${error}`)); | |
} | |
jwt.verify(token, key, options, function (err, decoded) { | |
if (err) { | |
return callback( | |
new Error(`Unable to verify Azure AD token. Error: ${err}`), | |
); | |
} | |
checkJwtReuse(decoded); | |
const decodedEmailOrUsername = decoded.email | |
? decoded.email | |
: decoded.preferred_username; | |
const emailVerified = validator.isEmail(decodedEmailOrUsername); | |
if (decodedEmailOrUsername && decodedEmailOrUsername === email) { | |
return callback(null, { | |
user_id: `${decoded.sub}`, | |
email: decodedEmailOrUsername, | |
email_verified: emailVerified, | |
}); | |
} else { | |
return callback(new Error("Unable to match email with token subject.")); | |
} | |
}); | |
}); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment