Rules to actions migration, idToken claim not being passed through

Hi, I’m trying to migrate from rules to actions. The guide was pretty great and I think i’ve got everything good to go. However my idToken is not being set anymore.

Here is the rule I was using:

function(user, context, callback) {
  const fetch = require('node-fetch');
  // call  our login lambda
  fetch('https://mydomain/i/login', {
    method: 'POST',
    headers: { authorization: configuration.MYTOKEN },
    body: JSON.stringify({ user }),
    timeout: 15000
  })
  .then(res => {
    if (!res.ok) {
      res.json().then((errorData) => {
        // non 2xx status code
        console.log('ERROR', errorData);
        return callback(new Error(errorData));
      });
    }
    res.json().then((data) => {
      const { smplrspace, hasura } = data;
      // add custom data
      const smplrNamespace = "https://smplrspace.com/jwt/claims";
      context.idToken[smplrNamespace] = smplrspace;
      // add hasura token
      const hasuraNamespace = "https://hasura.io/jwt/claims";
      context.accessToken[hasuraNamespace] = hasura;
      // finish
      console.log(`Login: ${user.name} (${user.email})`);
      callback(null, user, context);
    });
  })
  .catch(error => {
    console.log('ERROR', error);
    return callback(new Error(error));
  });
}

and here is the action code:

const fetch = require('node-fetch') // version 2.6.1

exports.onExecutePostLogin = async (event, api) => {
  // call  our login lambda
  fetch('https://mydomain/i/login', {
    method: 'POST',
    headers: { authorization: event.secrets.MYTOKEN },
    body: JSON.stringify({ user: event.user }),
    timeout: 15000,
  })
    .then((res) => {
      if (!res.ok) {
        res.json().then((error) => {
          // non 2xx status code
          console.log('ERROR', error)
          return api.access.deny(error.message)
        })
      }
      res.json().then((data) => {
        const { smplrspace, hasura } = data
        // add custom data
        const smplrNamespace = 'https://smplrspace.com/jwt/claims'
        api.idToken.setCustomClaim(smplrNamespace, smplrspace)
        // add hasura token
        const hasuraNamespace = 'https://hasura.io/jwt/claims'
        api.accessToken.setCustomClaim(hasuraNamespace, hasura)
        // finish
        console.log(`Login: ${event.user.name} (${event.user.email})`)
        return
      })
    })
    .catch((error) => {
      console.log('ERROR', error)
      return api.access.deny(error.message)
    })
}

The idToken appears unmodified in my frontend code (no changes there). Any idea?

Thanks in advance

Hi, any help? Is there any support we can reach out to? If not, how to migrate?

1 Like

Hey there @tibotiber!

Sorry for the delayed response here, but wanted to see if you were able to get this sorted? Is custom claim added reliably?

If your subscription allows for it, you can always open up a ticket at https://support.auth0.com/

Hi @tyf thanks for reaching out. No I haven’t solved this yet. Any help would be welcome :slight_smile:

1 Like

Happy to help!

  res.json().then((data) => {
        const { smplrspace, hasura } = data
        // add custom data
        const smplrNamespace = 'https://smplrspace.com/jwt/claims'
        api.idToken.setCustomClaim(smplrNamespace, smplrspace)
        // add hasura token
        const hasuraNamespace = 'https://hasura.io/jwt/claims'
        api.accessToken.setCustomClaim(hasuraNamespace, hasura)
        // finish
        console.log(`Login: ${event.user.name} (${event.user.email})`)
        return
      })

Is the access token custom claim set consistently in the same .then() where the ID token custom claim isn’t? Nothing in particular stands out in your code, but I’m wondering if it’s an issue with the nested .then() statements and an early return.

1 Like

Seeing the length of the response alone, the access token claim is also not set.

Your comment about an early return was a great lead, I’ve switched to using async/await instead of .then() as it’s a lot clearer what happens and it fixed my issue :tada:. I’m guessing the rules used an explicit call to the callback while an implicit return could end execution in an action, or something like that :man_shrugging:.

Thanks a lot for the help @tyf :pray:. Truly appreciate it :slightly_smiling_face:.

In case it helps anyone in future, here is the working code:

const fetch = require('node-fetch'); // version 2.6.1

exports.onExecutePostLogin = async (event, api) => {
  // call  our login lambda
  try {
    const res = await fetch('https://mydomain/i/login', {
      method: 'POST',
      headers: { authorization: event.secrets.MYTOKEN },
      body: JSON.stringify({ user: event.user }),
      timeout: 15000
    });
    if (!res.ok) {
      // non 2xx status code
      const error = await res.json();
      console.log('ERROR', error);
      return api.access.deny(error.message);
    }
    const { smplrspace, hasura } = await res.json();
    // add custom data
    const smplrNamespace = "https://smplrspace.com/jwt/claims";
    api.idToken.setCustomClaim(smplrNamespace, smplrspace);
    // add hasura token
    const hasuraNamespace = "https://hasura.io/jwt/claims";
    api.accessToken.setCustomClaim(hasuraNamespace, hasura);
    // finish
    console.log(`Login: ${event.user.name} (${event.user.email})`);
    return;
  } catch (error) {
    console.log('ERROR', error);
    return api.access.deny(error.message);
  }
};

:v:

1 Like

Awesome! I’m glad async/await did the trick :slight_smile: Thanks for sharing the working code, very helpful! :pray:

1 Like