简体   繁体   中英

Why does this verified JSON Web Token (JWT) output as undefined?

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?

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.

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);

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM