Implementing Device Tracking for Logged-In Users in NodeJS
In this guide, learn how to enhance user security by implementing device tracking in a NodeJS application. We'll walk through capturing device details, generating unique identifiers with UUID, and storing trusted devices using MongoDB, ensuring tokens are tied to specific, secure devices.

In today’s digital landscape, user security is paramount. One effective way to enhance security is by implementing device tracking for logged-in users. This feature helps monitor and control which devices can access a user’s account, adding an extra layer of protection. In this guide, we’ll walk through how to implement device tracking in a NodeJS application using Express, JWT (JSON Web Tokens), and MongoDB.
Overview
We will focus on tracking devices that users log in from. This involves:
- Identifying Devices: Capturing details like device type, browser, operating system, and IP address.
- Generating Unique Device Identifiers: Using UUIDs to uniquely identify each device.
- Storing Trusted Devices: Saving device information in a database for future reference.
- Handling Authentication and Tokens: Ensuring that tokens are associated with specific devices for security.
By the end, users will be able to track the devices they’ve logged in from, and the system will store this information in a secure manner.
Prerequisites
Before getting started, ensure you have the following:
- NodeJS installed.
- Express framework set up.
- MongoDB for data persistence.
- Familiarity with authentication using JWT.
If you need some help with your NodeJS and Express Project, you can always visit this page, where I am listing all the NodeJS concepts and techniques to help you build your project.

Step 1: Setting Up Device Information Capture
We need to capture device details like browser, operating system, platform, and IP address. For this, we’ll create a middleware that collects and attaches this information to the request object.
const collectRequestDetails = (
req: Request,
res: Response,
next: NextFunction,
) => {
const clientIp = requestIp.getClientIp(req);
const ua = useragent.parse(req.headers["user-agent"]);
(req as ExtendedRequest).requestDetails = {
ip: clientIp || "",
browser: ua.browser,
browser_version: ua.version,
os: ua.os,
platform: ua.platform,
is_mobile: ua.isMobile,
is_desktop: ua.isDesktop,
is_tablet: ua.isTablet,
};
next();
};
export default collectRequestDetails;
Here, we use the useragent library to parse the user-agent string and request-ip to capture the client’s IP address. These details are added to the request object for further use.
Step 2: Generating Unique Device Identifiers
Each device needs a unique identifier. We can generate this using the UUID library. In this middleware, we’ll check if the user already has a stored device ID in cookies. If not, we generate a new one.
const generateFingerprint = async (
req: Request,
res: Response,
next: NextFunction,
) => {
try {
const existingDeviceId = req.cookies.deviceId;
if (!existingDeviceId || existingDeviceId === "undefined") {
const deviceId = uuidv4();
(req as ExtendedRequest).deviceId = deviceId;
} else {
(req as ExtendedRequest).deviceId = existingDeviceId;
}
} catch (error) {
console.log("Error Fetching Device ID");
}
next();
};
export default generateFingerprint;
The UUID ensures that each device gets a unique identifier. This ID will later be associated with the user's session and stored in the database.
Step 3: Handling User Login and Tracking Devices
Now that we can capture device details and generate a unique identifier, we need to store this information whenever a user logs in. Here's an example of how we handle user login:
export const loginUser = async (req: Request, res: Response) => {
try {
// Other Logic for the Controller
const deviceId = (req as ExtendedRequest).deviceId;
const deviceInfo = (req as ExtendedRequest).requestDetails;
// Save the device information in the database
if (deviceId) {
await TrustedDeviceModel.findOneAndUpdate(
{ user_id: user._id, device_id: deviceId },
{
user_id: user._id,
device_id: deviceId,
browser: deviceInfo?.browser,
os: deviceInfo?.os,
platform: deviceInfo?.platform,
is_mobile: deviceInfo?.is_mobile,
is_desktop: deviceInfo?.is_desktop,
access_token: accessToken,
refresh_token: refreshToken,
},
{ upsert: true, new: true },
);
}
} catch (error) {
console.error("Error during login:", error);
res.status(500).json({ error: "Internal server error" });
}
};
In this login handler:
- We find the user by email or username.
- Verify the password.
- If the credentials are correct, we generate an access token and a refresh token.
- We store the device information (like browser, OS, and platform) in the TrustedDeviceModel collection along with the tokens.
Step 4: Managing Token Responses
We differentiate between mobile app users and web users by using headers to send the tokens back either in the response body or as cookies.
// For Web Applications
res.cookie("deviceId", deviceId, {
secure: true,
httpOnly: true,
sameSite: "none",
priority: "high",
});
// For Mobile Applications
res.status(200).json({
message: "Login successful",
accessToken: accessToken,
refreshToken: refreshToken,
isVerified: isVerified,
deviceId: deviceId,
mfaEnabled: mfaSecret ? true : false
});
Conclusion
By implementing device tracking in a NodeJS application, you can greatly enhance the security of your platform. With the approach outlined above, you can store detailed information about devices that log into user accounts, ensuring that tokens and sessions are tied to specific, trusted devices.
This feature is not only a great way to protect users but also opens up possibilities like allowing users to view and manage their logged-in devices, receive notifications of suspicious logins, and more.
That's it for Today, See ya 👋