Node.js Express JWT Authentication with MongoDB & Roles
This tutorial teaches you how to build a secure Node.js and MongoDB backend with JWT Authentication and Authorization.
Lukas
Created: January 15, 2025
Updated: January 17, 2025
1. Introduction#
In this tutorial, we will build a secure backend application using Node.js and MongoDB that supports user authentication (registration and login) and authorization with JSON Web Tokens (JWT). By the end of this guide, you will understand how to:
Implement a secure flow for user signup and login using JWT.
Structure a Node.js Express application with modern middlewares for CORS, authentication, and authorization.
Configure Express routes to integrate JWT seamlessly.
Define Mongoose models for managing users and roles.
Interact with a MongoDB database using Mongoose.
This comprehensive guide ensures you have all the necessary information to implement the application independently, following the latest best practices and leveraging modern technologies.
2. Token-Based Authentication#
2.1 Understanding JWT#
JSON Web Tokens (JWT) are a compact and self-contained way for securely transmitting information between parties as a JSON object. Unlike session-based authentication, where session data is stored on the server, JWTs are stored on the client side (e.g., in Local Storage for browsers) and eliminate the need for additional backend sessions or authentication modules for different clients.
A JWT consists of three parts:
Header: Contains the type of token and the signing algorithm.
Payload: Contains the claims or the data you want to transmit.
Signature: Ensures the token hasn't been altered.
The structure follows the header.payload.signature format. Clients typically attach JWTs in the Authorization header with the Bearer prefix:
2.2 Advantages of Token-Based Authentication#
Scalability: No need to store session data on the server.
Flexibility: Suitable for Single Page Applications (SPAs), mobile apps, and other clients.
Security: Signed tokens ensure data integrity and authenticity.
3. Project Structure#
Here's the directory structure for our Node.js, Express, and MongoDB application:
Run the application using the start script defined in package.json:
You should see console logs indicating that the server is running and connected to MongoDB:
Successfully connected to MongoDB.
Added 'user', 'admin', and 'moderator' to roles collection.
Server is running on port 8080.
5.2 Create a local MongoDB instance#
In case you don't have a MongoDB instance to use for testing available, you can create a temporary one using the following
docker command:
5.2 Test the API Endpoints#
Use tools like Postman or cURL to interact with the API.
5.2.1 Register a New User#
Endpoint:POST /api/auth/signup
Body:
Response:
Note: All users are assigned the user role by default. More privileged roles should not be obtained through registration,
but directly through database access.
5.2.2 Login#
Endpoint:POST /api/auth/signin
Body:
Response:
5.2.3 Access Public Resource#
Endpoint:GET /api/test/all
Response:
Public Content.
5.2.4 Access Protected Resource (User)#
Endpoint:GET /api/test/user
Headers:
Authorization: Bearer <jwt_token>
Response:
User Content.
5.2.5 Access Admin Resource#
Endpoint:GET /api/test/admin
Headers:
Authorization: Bearer <jwt_token>
Response:
Note: Only users with the admin role can access this endpoint.
5.2.6 Access Moderator Resource#
Endpoint:GET /api/test/mod
Headers:
Authorization: Bearer <jwt_token>
Response:
Note: Only users with the admin role can access this endpoint.
5.3 Handling Errors#
Invalid Credentials: Returns a 401 status with an error message.
Unauthorized Access: Returns a 403 status if the user lacks the necessary role.
Missing Token: Returns a 403 status indicating no token was provided.
Expired or Invalid Token: Returns a 401 status indicating unauthorized access.
Want to find out how many people can use passkeys?
Building a secure authentication and authorization system involves several critical factors:
6.1 Protecting the Secret Key#
Ensure that your JWT secret key (auth.config.js) is kept secure. In production environments, use environment variables or a secure secrets manager to store sensitive information.
6.2 Password Security#
Hashing: Passwords are hashed using bcryptjs before storage to prevent plain-text passwords from being exposed.
Salting: Bcrypt automatically handles salting, adding an extra layer of security against rainbow table attacks.
6.3 Token Security#
Expiration: JWTs have an expiration time (expiresIn: 86400 seconds) to limit the window of opportunity for token misuse.
Validation: Tokens are validated on each request to protected endpoints to ensure authenticity and integrity.
6.4 Role-Based Access Control (RBAC)#
Implement RBAC to restrict access to resources based on user roles. This ensures that users can only access what they are permitted to.
6.5 Error Handling#
Provide meaningful error messages without exposing sensitive information. Always handle errors gracefully to prevent potential leaks.
6.6 HTTPS#
Always use HTTPS in production to encrypt data in transit, protecting tokens and sensitive information from interception.
6.7 Rate Limiting and Throttling#
Implement rate limiting to protect against brute-force attacks and denial-of-service (DoS) attempts.
7. Conclusion#
Congratulations! You've successfully built a secure backend application using Node.js and MongoDB with robust user authentication and authorization using JWT. This setup ensures that your application can handle user registration, login, and role-based access control efficiently and securely.
Next Steps#
Implement Refresh Tokens: Enhance security by implementing refresh tokens to allow users to obtain new access tokens without re-authenticating.
Build a Frontend Client: Develop a frontend application using frameworks like React, Angular, or Vue.js to interact with your backend API.
Expand Role Hierarchies: Create more granular roles and permissions to better suit your application's needs.
Deploy to Production: Move your application to a production environment, ensuring all security best practices are followed.
Happy coding!
Table of Contents
Enjoyed this read?
🤝 Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.