Tracking API calls by User ID in Node.js

Tracking API calls by anonymous usage is only part of the story when it comes to leveraging API analytics and metrics. A lot more value can come from knowing exactly what users are using specific endpoints and how they are using them.

In order to track API calls and attribute them to a user, the API calls must be authenticated. For this particular example, I’m going to use a JSON Web Token, also referred to as a “JWT”. The JWT should be attached to the request. The specific field we will use to track the user is the JWTs id field.

I will be working from the Node.js code example from a previous guide, available here. To get user tracking working I will:

  • Configure my servers Moesif middleware to use the user ID coming from a JWT
  • Configure my endpoints to accept a JWT within the request
  • Attach a JWT to my request, and send it to the API

A few things to mention in this guide, before we start.

  1. I will be generating a JWT from jwt.io. Normally you would use the authentication flow from your app in order to generate this upon login, or by other means that do not require manual creation. In order to make things easier though, I have opted for manual creation. You will want to ensure that your JWT does have the required fields though in order to make user identification work.

  2. This example API is not secured. It does require that a JWT is passed with the request but we are not doing any type of authorization checks in this example. When publishing an API to production, likely you will want to make sure you have the correct authorization flows in place.

  3. Our example assumes that your server and API are already integrated with Moesif. If you still need to integrate your API with Moesif, please take a look at our Node.js integration guide before proceeding if you want to follow along.

With that said, let’s jump into our example!

Step 1: Getting Started

Below is the code for our sample API. It is just a very simple, single endpoint, built with Node.js and Express. As mentioned earlier, this server has already been integrated with Moesif.

Once your backend is integrated with Moesif, you’ll begin to see events roll in. Those events will look like this on the Moesif Events dashboard:

Moesif Metrics screen requests without a userID

You’ll notice that the User ID field is blank. This means that these events are not tagged to a specific user. Therefore, we cannot leverage user-specific metrics.

The code for this server implementation currently looks like this:

// app.js

const moesif = require('moesif-nodejs');

const app = express()
const port = 5000

const moesifMiddleware = moesif({
 applicationId: 'MOESIF_APPLICATION_ID',
});

app.use(moesifMiddleware);

app.get('/test',
 (_req, res) => {
   res.status(200)
   res.send('this is a response');
 }
)

app.listen(port, () => {
 console.log(`Example app listening at http://localhost:${port}`);
})

You will see under moesifMiddleware our configuration only includes the Moesif Application ID. In order for us to configure user tracking, we need to add a few lines of code to the middleware configuration.

Step 2: Adding User Tracking to Our Moesif Middleware

In order to add user tracking to our configuration, we need to supply an identifyUser parameter to the middleware. Doing that, our configuration object will now look like this:

// app.js

const moesifMiddleware = moesif({
 applicationId: 'MOESIF_APPLICATION_ID',

 // Optional hook to link API calls to users
 identifyUser: function (req, _res) {
   return req.auth ? req.auth.id : undefined;
 },
});

This identifyUser function will parse out the field from the request you want to use to identify the user. The decoded JWT payload is available on the request via the auth property. req.auth.id is a context variable set by the express-jwt middleware by reading the sub field of the JWT. This is the value we will use as our user identifier in Moesif.

NOTE: you don’t have to follow this convention exactly. You could pull the unique identifier from any part of the request, including the header, if needed. I am following this convention as it has become a standard field for passing a user’s ID through a JWT. The only thing necessary is to have the users ID be a unique and unchanging value.

With the code we supplied, Moesif will now be able to attach a user ID to an API request when the middleware intercepts the request.

We now need to configure out endpoints to use the JWT. For that, we will use Auth0’s express-jwt package.

Step 3: Adding in the express-jwt Dependency

To add in the express-jwt dependency I will use npm. In a terminal, run the following npm install command:

npm install express-jwt

Once this command completes, the express-jwt package will be added to node_modules and ready to use. Our package.json file’s dependencies object will be updated and, at the time of writing, looks like this:

// package.json

"dependencies": {
  "express": "^4.18.2",
  "express-jwt": "^8.4.1",
  "moesif-nodejs": "^3.3.2"
}

Now we can begin to plug it into our code.

Step 4: Implementing express-jwt

In our code, we will add the dependency at the top, like so:

// app.js

const { expressjwt: expressjwt } = require("express-jwt");

Now we will add in a basic usage to our endpoint. To use the JWT in our endpoint, we will add it as the second parameter.

// app.js

app.get('/test',
 expressjwt({ secret: 'shhhhhhared-secret', algorithms: ['HS256'] }),
 (_req, res) => {
   res.status(200)
   res.send('this is a response');
 }
)

Now our endpoint will enforce the incoming request to have a valid JWT attached to it.

Note: by adding the JWT function before our original handler, that function will be called first, followed by the original handler. For more details on how this works, check out the Express documentation.

The completed server code now looks like this:

// app.js

const express = require('express')
const moesif = require('moesif-nodejs');
const { expressjwt: expressjwt } = require("express-jwt");

const app = express()
const port = 5000

const moesifMiddleware = moesif({
 applicationId: 'MOESIF_APPLICATION_ID',

 // Optional hook to link API calls to users
 identifyUser: function (req, _res) {
   return req.auth ? req.auth.id : undefined;
 },
});

app.use(moesifMiddleware);

app.get('/test',
 expressjwt({ secret: 'shhhhhhared-secret', algorithms: ['HS256'] }),
 (_req, res) => {
   res.status(200)
   res.send('this is a response');
 }
)

app.listen(port, () => {
 console.log(`Example app listening at http://localhost:${port}`);
})

Our next steps are to generate our JWT to attach to our request.

Step 5: Creating the JWT

In this specific example, I’ll be using a JWT that contains an id in its payload. My JWT looks like this:

example text

I’ve created a JWT through jwt.io. Jwt.io allows you to create a JWT and edit the fields without having to use an Identity Provider or other source to create one. I’ve added a sample id field to the payload of my generated JWT. Now, I’ll attach the JWT to the request in Postman.

Step 6: Sending a Request Through Postman

After opening up Postman, we will plug in the endpoint URL for our GET request. We will also go to the Authorization tab for the request and attach our JWT in the Token field. Also note that the Type field should be set to “Bearer”.

example text

Once the JWT is copied in, your request should look like this:

example text

Now, send off the request. At this point, the request will be received by the server. Once at the server, the following will occur: the JWT id field will be parsed out using the Moesif middlewares identifyUser function and attached to the metric in Moesif.

Step 7: Verifying User Tracking

In Moesif, our request should be showing in the Events dashboard. Now we can see that a userID has been bound to the request.

You’ll see that the id passed in our JWT has now become the userID attached to the request we sent.

example text

At this point, we are now able to start leveraging user-specific metrics instead of having all of our data be anonymous. This can help to power many of the more advanced and valuable features within Moesif.

From Moesif

Other

Updated: