auth0 / express-jwt

connect/express middleware that validates a JsonWebToken (JWT) and set the req.user with the attributes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Moving from 6.1.2 to 7.4.2 breaks

nsshunt opened this issue · comments

When I upgraded from v 6.1.2 to 7.4.2 I get this error;

TypeError: cb is not a function

Error occurs within expressJwtSecret @ highlighted line

module.exports.expressJwtSecret = function (options) {
if (options === null || options === undefined) {
throw new ArgumentError('An options object must be provided when initializing expressJwtSecret');
}

const client = new JwksClient(options);
const onError = options.handleSigningKeyError || handleSigningKeyError;

return function secretProvider(req, header, payload, cb) {
if (!header || !supportedAlg.includes(header.alg)) {
### return cb(null, null);
}

client.getSigningKey(header.kid)
  .then(key => {
    cb(null, key.publicKey || key.rsaPublicKey);
  }).catch(err => {
    onError(err, (newError) => cb(newError, null));
  });

};
};

In 7.2.1, the secretProvider(req, header, payload, cb) gets;
req - ok (appears to be the req object)
header - this is actually the decoded token
payload = undefined
cd = undefined

So the caller is passing the wrong parameters.

Further, the caller is using 'option 3' when invoking this function.

Can confirm that it also breaks for me too after simply upgrading (and changing the imports). I just get a "expired token" error every time

The doc was outdated in 7.2.1, sorry about that. I made a major version (v7) because there are breaking changes. I fixed the readme arround 7.4

The secret function receives two parameters only:

  • req: the express.js request
  • token: contains payload and header

https://github.com/auth0/express-jwt#retrieve-key-dynamically

in your case, your function can be replaced to this:

module.exports.expressJwtSecret = function (options) {
  if (options === null || options === undefined) {
    throw new ArgumentError('An options object must be provided when initializing expressJwtSecret');
  }

  const client = new JwksClient(options);
  const onError = options.handleSigningKeyError || handleSigningKeyError;

  return function secretProvider(req, token) {
    const { header } = token;
    if (!header || !supportedAlg.includes(header.alg)) {
      return;
    }
    return client.getSigningKey(header.kid)
      .then(key => {
        return key.publicKey || key.rsaPublicKey;
      }).catch(err => {
        return new Promise((resolve, reject) => {
          onError(err, (newError) => reject(newError));
        });
      });
  }
};

+1, rolled back until this integration is fixed

The following rough replacement works for us for now until the integration is fixed. (I removed the options check and onError callback, as neither are needed in our case.)

import { GetVerificationKey } from 'express-jwt';
import { Jwt, Secret } from 'jsonwebtoken';
import { ExpressJwtOptions, JwksClient } from 'jwks-rsa';

export function expressJwtSecret(options: ExpressJwtOptions): GetVerificationKey {
  const supportedAlg = require('jwks-rsa/src/integrations/config.js') as string[];
  const client = new JwksClient(options);
  return async function secretProvider(_req, token: Jwt | undefined): Promise<Secret> {
    if (token) {
      const { header } = token;
      if (header && supportedAlg.includes(header.alg)) {
        const key = await client.getSigningKey(token.header.kid);
        return key.getPublicKey();
      }
    }
    return '';
  };
}

We're currently on:

  "express-jwt": "7.4.3",
  "jsonwebtoken": "8.5.1",
  "jwks-rsa": "2.0.5",
  "@types/jsonwebtoken": "8.5.8",

thanks for the heads up. I will try to fix jwks-rsa

I just send a PR, you can use npm i "jfromaniello/node-jwks-rsa#express_jwt_7" until it gets merged.

Fixed in jwks-rsa@2.1

Thanks a lot for the fix, José!

@jfromaniello, there is a small typing issue. The newest versions of express-jwt use GetVerificationKey as the type of this callback. SecretCallbackLong seems to be the interface that was used by @types/express-jwt up to express-jwt@7.

@rene-leanix I don't understand this.. Where is that SecretCallbackLong ? Thanks!

@jfromaniello, it's being imported here and used here. This should be changed to GetVerificationKey. (SecretCallback may also need to be replaced.)

Missing interface definitions are just interpreted as any, so shouldn't lead to TS errors. In our case, ESLint picked this up as we've got a rule to avoid assignments of any types. A temporary workaround was to cast it to GetVerificationKey.

@rene-leanix you are absolutely right. I was able to reproduce the issue ,but as I wanted to leave jwks-rsa compatible with the previous version of express-jwt , I added a type alias for SecretCallback and SecretCallbackLong.

So, the fix the issue just install express-jwt@7.6.