Last active
December 19, 2022 00:36
-
-
Save jatinvaidya/24347fd64342b4bbe8ebbe3b16bd2944 to your computer and use it in GitHub Desktop.
Auth0 M2M Hook: Access Token Exchange Controls
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
/** | |
@param {object} client - information about the client | |
@param {string} client.name - name of client | |
@param {string} client.id - client id | |
@param {string} client.tenant - Auth0 tenant name | |
@param {object} client.metadata - client metadata | |
@param {array|undefined} scope - array of strings representing the scope claim or undefined | |
@param {string} audience - token's audience claim | |
@param {object} context - additional authorization context | |
@param {object} context.webtask - webtask context | |
@param {function} cb - function (error, accessTokenClaims) | |
*/ | |
////////// DRAFT CODE //////////////// | |
////////// 2B improved /////////////// | |
module.exports = function(client, scope, audience, context, cb) { | |
// extract AT from the on_behalf_of field in the body | |
let sourceAccessToken = context.body.subject_token; | |
console.debug(`sourceAccessToken: ${sourceAccessToken}`); | |
let scopeMapping = JSON.parse(client.metadata[audience]); | |
console.info(`scopeMapping: ${JSON.stringify(scopeMapping)}`); | |
// Verify the Source Access Token (aka subject_token) | |
if (!!scopeMapping) { | |
// validate sourceAccessToken as per usual best practices (not shown) | |
// Verify using getKey callback | |
// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys. | |
var jwt = require("jsonwebtoken"); | |
var jwksClient = require("jwks-rsa"); | |
var client = jwksClient({ | |
// hardcoded here, but we can use JWKS URI for other "trusted" Authorization Servers | |
// to verify their JWT Access Tokens | |
jwksUri: "https://jv-delegation.au.auth0.com/.well-known/jwks.json", | |
}); | |
function getKey(header, callback) { | |
client.getSigningKey(header.kid, function (err, key) { | |
var signingKey = key.publicKey || key.rsaPublicKey; | |
callback(null, signingKey); | |
}); | |
} | |
jwt.verify( | |
sourceAccessToken, | |
getKey, | |
{ algorithms: ["RS256"] }, | |
function (err, decodedSourceAccessToken) { | |
if (!!err) { | |
// bad or untrusted sibject_token | |
return cb(new InvalidRequestError("Invalid subject_token")); | |
} | |
// get the target resource server identifier | |
let targetResourceServerIdentifier = audience; | |
console.info( | |
`targetResourceServerIdentifier: ${targetResourceServerIdentifier}` | |
); | |
// get the target scopes requested | |
let targetScopesRequested = scope || []; | |
console.info(`targetScopesRequested: ${targetScopesRequested}`); | |
// get access control matrix for this resource server | |
// sample: | |
/*{ | |
"read:bills": [ | |
"read:reports", | |
"create:reports" | |
], | |
"update:bills": [ | |
"update:reports" | |
] | |
} */ | |
let sourceScopesGranted = decodedSourceAccessToken.scope || ""; | |
sourceScopesGranted = sourceScopesGranted.split(" "); | |
console.info(`sourceScopesConsented: ${sourceScopesGranted}`); | |
// delegated call from this source-api to target-api is allowed, | |
// now do scope related checks | |
let targetScopesAllowed = []; | |
sourceScopesGranted.forEach((sourceScope) => | |
targetScopesAllowed.push(...scopeMapping[sourceScope]) | |
); | |
console.info(`targetScopesAllowed: ${targetScopesAllowed}`); | |
// intersection of requested and allowed scopes | |
let targetScopesResultant = targetScopesRequested.filter( | |
(targetScope) => targetScopesAllowed.includes(targetScope) | |
); | |
console.info(`targetScopesResultant: ${targetScopesResultant}`); | |
let accessToken = { | |
scope: targetScopesResultant, | |
on_behalf_of: decodedSourceAccessToken.sub, | |
}; | |
cb(null, accessToken); | |
} | |
); | |
} else { | |
return cb(new InvalidRequestError("Unauthorized to get an access token to call target api")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment