Reputation: 2043
I'm trying to decode a JWT id_token
using jwks-rsa and jsonwebtoken but the result is returning as undefined
.
I know this has something to do with callbacks, and the fact that I need to wait for a response from the getKey
function but I can't wrap my head around how to structure the code to make that happen.
This is what I have so far...
function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.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);
});
}
var jwt = require('jsonwebtoken');
jwt.verify(id_token, getKey, { algorithms: ['RS256'] }, function(err, decoded) {
if (err) {
console.log(err);
} else {
return decoded;
}
});
const bubble_obj = do_thing();
console.log(bubble_obj); //This is `undefined`
The console.log(bubble_obj);
outputs as undefined
.
I know the problem with the above code is due to the nature of callbacks and asynchronous code, because if I move the console.log
inside the jwt.verify
call it will show the correctly decoded token.
See here for that example...
function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.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);
});
}
var jwt = require('jsonwebtoken');
jwt.verify(id_token, getKey, { algorithms: ['RS256'] }, function(err, decoded) {
if (err) {
console.log(err);
} else {
console.log(decoded); //When moved here, it prints the correctly decoded token
return decoded;
}
});
const bubble_obj = do_thing();
So how do I make it return the correctly decoded token?
Upvotes: 2
Views: 3688
Reputation: 106
You can use a promise to verify the JWT with a JWK callback and promise as follows. You will need to wrap the following in an async
function to use the result of the verify_jwks()
function:
const token = "REDACTED";
var jwksClient = require('jwks-rsa');
// Creates a JWKS Client with a rate limit that
// limits the number of calls to our JWKS endpoint
var client = new JwksClient({
jwksUri: 'https://REDACTED.com/.well-known/jwks.json',
rateLimit: true,
jwksRequestsPerMinute: 10, // Default Value
cache: true, // Default Value
cacheMaxEntries: 5, // Default value
cacheMaxAge: 600000, // Defaults to 10m
});
// Verifies the JWKS asynchronously, returns Promise
async function verify_jwks() {
function getKey(header, callback) {
// Callback that returns the key the corresponding key[kid]
client.getSigningKey(header.kid, function(err, key) {
const signingKey = key.getPublicKey() || key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
// Returns a Promise with verification result or error
return new Promise((resolve,reject) =>
jsonwebtoken.verify(token,getKey, {
algorithms: ["HS256", "RS256"]
},
function(err,decoded) {
return err ? reject(err) : resolve(decoded);
}
));
}
let result;
await verify_jwks()
.then(decoded => result = decoded)
.catch(error => console.log(error));
console.log(result);
Upvotes: 0
Reputation: 74
you need to handle promise returned by jwt.verify. either use promise.then. or go with async/await.
async function do_thing(properties, context) {
const id_token = "REDACTED";
// Verify using getKey callback
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://REDACTED.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);
});
}
const jwt = require('jsonwebtoken');
return jwt.verify(id_token, getKey, { algorithms: ['RS256'] });
}
const decodedToken = await do_thing();
console.log("decoded token:", decodedToken);
Upvotes: 0
Reputation: 1677
You're not handling the asynchronous code correctly. The jwt.verify
method returns a Promise if you do not pass it the callback method.
If you use return jwt.verify(id_token, getKey, { algorithms: ['RS256'] })
inside the do_thing
function and call it like this do_thing().then((decodedToken) => console.log(decodedToken))
, it should work as expected.
Upvotes: 3