How can Node (express) API lookup email address from token?

Hi,

I’m trying to lookup the authenticated email address associated with a given Node request, but it’s not obvious from the docs how that’s done.

I have a web app client (SPA - single page app) which uses the passwordless auth system to provide the user’s web browser with an access token that includes a “sub” key like “email|54321abcd6789efh”, as well as an “email” key of “me@mydomain.com”. The frontend passes the token to the backend, so I would hope/expect the email is available in the “req.user” property but I only see a “sub” key (with content as shown previously).

The web app does a fetch() to my express app like this:

    const token = await auth0.getTokenSilently();
    const response = await fetch("/api/protected", {
      headers: {
        Authorization: `Bearer ${token}`
      }
    });

The backend services uses the following npm libraries:

  • express-jwt-authz
  • express-jwt
  • jwks-rsa
  • express-session

Here’s the meat of the backend:

// Authentication middleware. When used, the
// Access Token must exist and be verified against
// the Auth0 JSON Web Key Set
const checkJwt = jwt({
  // Dynamically provide a signing key
  // based on the kid in the header and 
  // the signing keys provided by the JWKS endpoint.
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `https://${authConfig.domain}/.well-known/jwks.json`
  }),
  
  // Validate the audience and the issuer.
  audience:  authConfig.audience,
  issuer: `https://${authConfig.domain}/`,
  algorithms: ['RS256']
});

app.get('/api/protected', checkJwt, (req, res) => {
  console.log(req.user);
  res.send({
    msg: "Your access token was successfully validated!"
  });
});

So, question -

Is there a way the backend can map { “sub”: “email|54321abcd6789efh” } to something like { “email”: “me@mydomain.com” } ?

Is there something else the backend needs to do so the req.user object automatically has the email field present?

Is there another JS server library function to call to get that email?

Thanks!

Other info:

  • Which verison of the SDK you are using? Latest
  • Which version of the platform are you facing this error on? Node 10.16
  • Was this code working before? Have you made any changes in the dashboard recently? No
  • Please capture and attach the stacktrace, it helps a lot! Doesn’t seem relevant here.
  • Please share the code that is causing the error. Done.
  • Can you share a minimum reproducible? If this isn’t enough, please let me know.

I’ve searched the docs / forums but am not seeing anything obvious. Help or pointers are greatly appreciated. Thanks!

Hi @techieshark,

You can’t quite edit a token after it leaves the auth server, so you will not be able to add anything to it once it is issued.

With that being said, there are a few ways to do this.

You can send the access token to the /userinfo endpoint:
https://auth0.com/docs/api/authentication#get-user-info

The node library for this call:
https://auth0.github.io/node-auth0/module-auth.AuthenticationClient.html#getProfile

You could also get email from the id token and send that with the request.

Finally, you could add the email to the access token via a custom claim in a rule.

Let me know if that makes sense. Each method may have a tradeoff, but I would probably consider them in the order I listed, but at the end of the day it is really up to you.

Thanks,
Dan

1 Like

Thanks Dan! That worked (going with the first suggestion of auth0 lib). Here’s what I’ve got now:

const AuthenticationClient = require('auth0').AuthenticationClient;
const authConfig = require('auth_config.json');
const auth0 = new AuthenticationClient({
  domain: authConfig.domain,
  clientId: authConfig.clientId,
});

function route(req, res) {
      const accessToken = req.headers.authorization.split(' ')[1]; // should be present & safe because auth0 middleware already validated auth token.

      const userProfile = await auth0.getProfile(accessToken);
      // https://auth0.github.io/node-auth0/module-auth.AuthenticationClient.html#getProfile
      
      if (!userProfile.email_verified) {
        return res.status(400).send({message: 'Email must be verified before proceeding'});
      }
     
      console.log('email: ', userProfile.email);
      ...
}

The above auth0 library request worked for me.


In case others are interested, I tried out the Rules option and that worked too:

Rule added to Auth0.com > admin > Rules

// See https://auth0.com/docs/architecture-scenarios/spa-api/api-implementation-nodejs#4-determine-the-user-identity
function (user, context, callback) {
  const namespace = 'https://my-url.com/';
  context.accessToken[namespace + 'email'] = user.email;
  callback(null, user, context);
}

Now available in Node app:

function route(req, res) {
      console.log('email: ', req.user['https://my-url.com/email`]);
     ...
}

Cheers,
Peter

4 Likes

Glad to hear this worked for you and thank you for the detailed response. It is certainly helpful for future users.

Cheers,
Dan

2 Likes

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.