Get Auth0 User Metadata in NodeJS/Express backend (ReactJS frontend login)

I have a ReactJS SPA (frontend) with NodeJS/Express (backend). My Auth0 login form is on the frontend. I would like to send user_metadata from the frontend (the User object, created when User logs in) to my backend. I need to use some of the user attributes to filter API calls on the backend (i.e. pull data from a table and filter based on user’s company name).

I setup a M2M app and a custom API in Auth0 to pass the appropriate tokens. I am able to POST the access token, but I receive a 404 error when I try to GET /api/v2/userinfo

Below is a sample of my code. Any help will be greatly appreciated:

// I am able to retrieve the access token
const myFunction = async function (req, res) {
  try {
    var opts = {
      method: "POST",
      url: "<my auth0 domain>/oauth/token",
      headers: { "content-type": "application/x-www-form-urlencoded" },
      data: new URLSearchParams({
        grant_type: "client_credentials",
        client_id: <my client id>,
        client_secret: <my client secret>,
        audience: "https://dev-tyofb4m1.us.auth0.com/api/v2/",
      }),
    };

    axios
      .request(opts)
      .then(function (response) {
        const accessToken = response.data.access_token;
        console.log("accessToken: ", accessToken);
      })
      .catch(function (error) {
        console.error(error);
      });
}

//But Axios returns 404 (Not Found) when i try to GET /api/v2/userinfo
    var opt = {
      method: "GET",
      url: "https://<my auth0 domain>/api/v2/userinfo",
      headers: {
        "content-type": "application/json",
        authorization: `Bearer ${accessToken}`,
      },
    };

    axios
      .request(opt)
      .then(function (res) {
        console.log(res.data);
      })
      .catch(function (error) {
        console.error(error);
      });

Just looking briefly at your code- the POST function is used to GET(return) your access token to you. You are not actually POSTing your access token, you are POSTing the information necessary to retrieve it to your frontend browser. Cheers,

1 Like

Hello @robliou01 ,

Thanks for responding. I am noticing a couple things that I am doing wrong:

  1. the https://my-domain/api/v2/userinfo endpoint is invalid. The /userinfo endpoint is actually on the Authentication API as opposed to the Management API. the correct endpoint is https://my-domain/userinfo. But, even when I change the GET call to the correct endpoint - I still receive a 401 (unauthorized) error.

  2. When I changed the endpoint to https://my-domain/api/v2/USER_ID and inserted an actual USER_ID at the end of the endpoint, I successfully retrieve that user’s metadata. This is great, but I can’t figure out how to dynamically insert the USER_ID, based on the current user’s metadata. This would be very simple to do on the frontend, but I can’t seem to figure out how to do this on the backend.

// ---- My GET method is making a call to the Authentication API endpoint ----//
// ---- II think I need to use and ID TOKEN to retrieve this info ??? ---- //

var options = {
            method: "GET",
            url: "https://my-domain/userinfo",
            headers: {
              "content-type": "application/json",
              authorization: `Bearer ${accessToken}`,
            },
          };

          axios
            .request(options)
            .then(function (response) {
              console.log("RES DATA: ", response.data);
            })
            .catch(function (error) {
              console.error(error);
            });

With that being said, I understand how to request an ACCESS_TOKEN…but, how do I retrieve an ID_TOKEN from the frontend when a user logs in (other than using the JWT/JWKS-RSA approach)?

Using the JWT/JWKS-RSA approach causes a conflict with one of my 3rd-party API calls.

Hey @carlos.anderson welcome to the community!

Have you considered adding user_metadata as a custom claim to the access token and going that route?

You can receive a 401 for a couple of reasons outlined in this post:

Keep us posted!

Hello @tyf ,

Thanks for your feedback. Yes, I have added user_metadata to custom claims via custom Action. (Code Snippet Below)

// Logic to Get/Set User Metadata to Access/ID Tokens
  if (event.authorization) {
    api.idToken.setCustomClaim(`${namespace}/givenname`, event.user.user_metadata.given_name);
    api.accessToken.setCustomClaim(`${namespace}/givenname`, event.user.user_metadata.given_name);

    api.idToken.setCustomClaim(`${namespace}/familyname`, event.user.user_metadata.family_name);
    api.accessToken.setCustomClaim(`${namespace}/familyname`, event.user.user_metadata.family_name);

    api.idToken.setCustomClaim(`${namespace}/bio`, event.user.user_metadata.bio);
    api.accessToken.setCustomClaim(`${namespace}/bio`, event.user.user_metadata.bio);

    api.idToken.setCustomClaim(`${namespace}/title`, event.user.user_metadata.title);
    api.accessToken.setCustomClaim(`${namespace}/title`, event.user.user_metadata.title);

    api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
    api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);

I have also successfully pulled the User object from JWT on most of my backend APIs, but one in particular (PowerBI Embedded API) crashes when I attempt to “verifyJwt” (Code Snippets Below)

//---- I initialize the required modules here ----//
const { expressjwt: jwt } = require("express-jwt");
const jwks = require("jwks-rsa");

//---- Able to successfully access the User object on calls to my Google BigQuery endpoints ----//
var verifyJwt = jwt({
  secret: jwks.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: "https://my-domain.auth0.com/.well-known/jwks.json",
  }),
  audience: "https://my-audience.io",
  issuer: "https://my-domain.auth0.com/",
  algorithms: ["RS256"],
});

router.get("/bqapi", verifyJwt, bqController.bq_get_bqapi);

//--- However, my PowerBI endpoint crashes when I attempt the same process ----//
//--- Possibly due to the fact that the PowerBI endpoint is making Asynchronous calls to the PBI API and the "verifyJwt" object is blocking access? I'm not sure ----//

//---- This Works and I am able to successfully bootstrap PBI Embedded Report ----//
router.get("/pbiapi", verifyJwt, pbiController.pbi_api);

//---- This Fails and I am unable to bootstrap PBI Embedded Report ----//
router.get("/pbiapi", verifyJwt, pbiController.pbi_api);

//--- This is the error message from PBI ----//
"Uncaught SyntaxError: Unexpected token 'C', "Cannot rea"... is not valid JSON
    at JSON.parse (<anonymous>)
    at Object.error (index.js:76:23)
    at c (jquery.min.js:2:28327)
    at Object.fireWith [as rejectWith] (jquery.min.js:2:29072)
    at l (jquery.min.js:2:79926)
    at XMLHttpRequest.<anonymous> (jquery.min.js:2:82355)"

That’s where I am stuck. I need to send the current User object from my ReactJS frontend to NodeJS/Express backend when users login, so that I can filter PBI Report config based on user attributes (i.e. “Company Name”). But, PBI crashes when I use “verifyJwt” and I receive an “Unauthorized” error when attempting to access User metadata vis /userinfo with an access_token.

I am looking into the “Auth0 Authorization Extension” as a possible solution. Any thoughts on that extension?

Thanks,
Carlos

If you are just looking to return information about the current user, I believe you can simply use the normalized user object, which does not require making an additional GET call to the management API.

To activate it, you simply instantiate it:

const { user } = useAuth0();

and then you can access properties of the user from within your code (i.e. {user.name}, {user.email}, etc.)

Hello @robliou01 ,

I need to use the user object on the backend, but I’m using the front end to authorize users. Can I install the Auth0 module on the backend as well and call the user object?

Carlos.

The approach that I’d try is as follows:

  1. From the front-end, instantiate the user object and save the user object as a variable
  2. define the route in the backend, while customizing it so that you can pass an object along the route as well
  3. call the route from the front-end, making sure to include the user object you’d want to pass along

I haven’t had to deal with this before, so not sure if this is the correct way. But, it’s what I would try, I hope that this is helpful.

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