Auth0 Home Blog Docs

Jwt.sign within rule generates invalid token frequently

token
jwt

#1

We have a rule in place that calls an API to enrich the final token given to the user during the authentication flow. Using jwt.sign within the rule fails about half the time (meaning the generated value is not a valid token).

function enrichTokenWithCtxUserRef(user, context, callback) {
  // if this is not an authentication for an api or this client
  // doesn't provide a signing_secret and me_endpoint then get out.
  if (!context.request.query.audience ||
    !context.clientMetadata.signing_secret ||
    !context.clientMetadata.me_endpoint
  ) {
    return callback(null, user, context);
  }

  var request = require('request@2.56.0');
  var userInfoToken = jwt.sign(
    {
      email: user.email,
      rand: Math.random()
    },
    context.clientMetadata.signing_secret,
    {
      expiresInMinutes: 5,
      audience: context.request.query.audience,
      issuer: 'https://' + context.request.hostname + '/'
    }
  );

  request.get({
      url: context.clientMetadata.me_endpoint,
      headers: {
        Authorization: 'Bearer ' + userInfoToken,
        'Content-Type': 'application/json'
      }
    },
    function (err, response, body) {
      if (err) {
        return callback(err);
      }

      var data;
      try {
        data = JSON.parse(body);
        if (!data.ok) {
          return callback(new UnauthorizedError(data.error_name + '::' + data.error_message));
        }
      } catch (e) {
        return callback(new Error(body));
      }

      if (data.message.is_staff) {
        context.accessToken.scope = 'is_staff'];
      }

      context.accessToken[context.request.query.audience + 'ctx_user_ref'] = data.message_ref.curie + ':' + data.message_ref.id;
      return callback(null, user, context);
    });
}

Has anyone been able to reliably create a jwt from within a rule?


#2

I have modified expiresInMinutes to be expiresIn as I noticed it was deprecated here https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md.

the issue is still present though.


#3

I have modified expiresInMinutes to be expiresIn as I noticed it was deprecated here https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md.

the issue is still present though.


#4

Although it was some time ago I already used jwt.sign from within a rule and did not experienced any issues when receiving and validating the generated token. However, when I did it, I did request a explicit version of the jsonwebtoken module instead of relying on the one that has built-in support and as such can be used without a require.

The recommendation here would be for you to explicitly request a version of that module and verify if you still observe issues. You can check the versions available within rules at:

https://tehsis.github.io/webtaskio-canirequire/#jsonwebtoken

For example, you could (and should even if this is not the root cause of the issue) do:

var jwt = require('jsonwebtoken@7.1.9');
var request = require('request@2.56.0');
// ...
// you may need to adapt the code to be compatible with the requested version

If fixing the version still leads to issues then at least we can reduce the scope of testing to a single version and in this case you should also update your question with additional information about what exactly constitutes an invalid token (an example would be great).


Call our API from a rule
#5

Pegging the jwt lib seems to have done the trick plus back dating the token to account for possible clock skew between Auth0 and our server. seems to be stable now with:

  var jwt = require('jsonwebtoken@7.1.9');
  var request = require('request@2.56.0');

  var userInfoToken = jwt.sign(
    {
      email: user.email,
      iat: Math.floor(Date.now() / 1000) - 2
    },
    context.clientMetadata.signing_secret,
    {
      expiresIn: 4,
      audience: context.request.query.audience,
      issuer: 'https://' + context.request.hostname + '/'
    }
  );

Thanks for the tip @jmangelo


#6