Skip to content

tabari86/user-management-service

Repository files navigation

User Management Service

CI Node.js Express MongoDB JWT bcrypt Swagger REST API Jest Supertest Docker GitHub Actions


A lightweight REST API for user registration, login, JWT authentication, protected profile management, admin user management and password reset workflows.


About the Project

User Management Service is a backend service built with Node.js, Express, MongoDB and JWT.

The project demonstrates a realistic user management API with registration, login, password hashing, JWT-based authentication, protected profile routes, admin user management, account status handling and password reset workflows.

It follows a modular backend structure using controllers, routes, middleware, services, utilities and Mongoose models.


Live Deployment

The API is deployed on Render and can be accessed here:

https://user-management-service-1jgc.onrender.com

Health check:

https://user-management-service-1jgc.onrender.com/health

Swagger API documentation:

https://user-management-service-1jgc.onrender.com/api-docs

Note: The service is hosted on Render's free tier. The first request after a period of inactivity may take a little longer because the service can spin down when idle.


Swagger Documentation

Swagger UI is available after starting the application:

http://localhost:3000/api-docs

Swagger Preview

Swagger UI


Features

Feature Description
User Registration Create a new user account with strong password validation
Password Hashing Passwords are hashed with bcrypt
Login Authenticate user credentials and return a JWT token
JWT Authentication Protect API routes with Bearer Token authentication
User Profile Get and update the current authenticated user profile
Password Change Change the current user's password after password verification
Forgot Password Request a password reset link by email
Reset Password Reset password with a time-limited reset token
Password Policy Enforce strong passwords for registration, change and reset
Admin User Management List users and manage account status
Account Status Control Activate or disable user accounts
MongoDB Store user data persistently
Swagger/OpenAPI Interactive API documentation
Automated Tests API testing with Jest and Supertest
Docker Support Containerized application and database
CI/CD Pipeline Automated test execution with GitHub Actions

Tech Stack

  • Node.js
  • Express.js
  • MongoDB
  • Mongoose
  • JWT
  • bcrypt
  • Nodemailer
  • Swagger / OpenAPI
  • Jest
  • Supertest
  • Docker
  • Docker Compose
  • dotenv
  • GitHub Actions

API Endpoints

Method Endpoint Description Auth
GET /health Check API service status No
POST /auth/register Register a new user No
POST /auth/login Login and receive JWT token No
POST /auth/forgot-password Request a password reset email No
POST /auth/reset-password Reset password with a valid reset token No
GET /users/me Get current user profile Bearer Token
PUT /users/me Update current user profile Bearer Token
PATCH /users/me/password Change current user password Bearer Token
GET /users List all users Admin only
PATCH /users/:id/status Activate or disable a user account Admin only

Security and Account Status Behavior

Protected endpoints require a valid Bearer token.

For every protected request, the API checks the current user record in the database. This means that user roles and account status are evaluated from the latest database state, not only from the JWT payload.

Disabled users cannot access protected endpoints, even if they still have an older valid token. This applies to regular users and admins.

If a user account no longer exists, protected requests return 404 Benutzer nicht gefunden.

This behavior prevents outdated tokens from keeping access after an account has been disabled, deleted, or downgraded.


Password Reset Behavior

The API supports a backend-only password reset flow.

A user can request a password reset link with POST /auth/forgot-password. If the email belongs to an active account, the API creates a reset token and sends a reset link by email.

For security reasons, the raw reset token is never stored in the database. Only a SHA-256 hash of the token is stored together with an expiration timestamp.

Password reset tokens expire after 15 minutes by default. The expiry time can be configured with PASSWORD_RESET_TOKEN_EXPIRY_MINUTES.

The API returns a generic response for unknown email addresses. This helps prevent user enumeration.

Disabled users cannot request or use password reset tokens.

After a successful password reset, the stored reset token hash and expiration timestamp are cleared so the same token cannot be reused.


Password Policy

The same strong password policy is applied to:

  • User registration
  • Password change
  • Password reset

Passwords must:

  • Be between 12 and 128 characters long
  • Include at least one lowercase letter
  • Include at least one uppercase letter
  • Include at least one number
  • Include at least one special character

Whitespace does not count as a special character.


Project Structure

user-management-service/
├── .github/
│   └── workflows/
│       └── test.yml
├── controllers/
│   ├── authController.js
│   └── userController.js
├── docs/
│   └── swagger-ui.png
├── middleware/
│   └── authMiddleware.js
├── models/
│   └── user.js
├── routes/
│   ├── authRoutes.js
│   └── userRoutes.js
├── services/
│   └── emailService.js
├── swagger/
│   └── userSwagger.js
├── tests/
│   ├── admin.api.test.js
│   ├── auth.api.test.js
│   └── health.test.js
├── utils/
│   └── passwordPolicy.js
├── .dockerignore  
├── .env.example
├── .gitignore
├── app.js
├── docker-compose.yml
├── Dockerfile
├── index.js
├── package.json
├── package-lock.json
└── README.md

Environment Variables

Create a local .env file based on .env.example.

PORT=3000
MONGODB_URI=mongodb://127.0.0.1:27017/user-management
JWT_SECRET=your_jwt_secret_here

APP_BASE_URL=http://localhost:3000

SMTP_HOST=sandbox.smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=your_mailtrap_username
SMTP_PASS=your_mailtrap_password
SMTP_FROM="User Management Service <no-reply@example.com>"

PASSWORD_RESET_TOKEN_EXPIRY_MINUTES=15

For local email testing, Mailtrap Email Sandbox can be used as an SMTP provider. Real SMTP credentials must be configured in the local .env file or in the Render environment settings. Secrets are not committed to the repository.


Installation

git clone https://github.com/tabari86/user-management-service.git
cd user-management-service
npm install

Run the Application

Make sure MongoDB is running locally.

npm start

Server:

http://localhost:3000

Swagger UI:

http://localhost:3000/api-docs

Docker

Run the complete application stack:

docker compose up --build

For the first startup, Docker will automatically:

  • Build the Node.js application image
  • Pull the MongoDB image
  • Create the required containers
  • Create a persistent MongoDB volume

Services:

  • Node.js application
  • MongoDB database

The API will be available at:

http://localhost:3000

Swagger UI:

http://localhost:3000/api-docs

Stop the containers:

docker compose down

Continuous Integration (CI)

This project uses GitHub Actions to automatically run the test suite on every push and pull request to the main branch.

Workflow steps:

  • Checkout repository
  • Setup Node.js
  • Install dependencies
  • Start MongoDB service
  • Run Jest and Supertest tests

This helps ensure that new changes do not break existing functionality.


Current Status

Implemented:

  • User registration
  • Login
  • JWT authentication
  • Protected profile route
  • Profile update route
  • MongoDB connection
  • Swagger documentation
  • Automated tests with Jest and Supertest
  • Dockerfile
  • Docker Compose setup
  • GitHub Actions CI workflow
  • Admin user management
  • Account activation and disabling
  • Password change endpoint
  • Forgot password flow
  • Reset password flow
  • Strong password policy
  • Mailtrap SMTP integration for password reset emails

Planned improvements:

  • Metrics endpoint
  • Refresh token flow

Example Requests

Register

curl -X POST http://localhost:3000/auth/register \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"Test User\",\"email\":\"testuser@example.com\",\"password\":\"TestPassword123!\"}"

Login

curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d "{\"email\":\"testuser@example.com\",\"password\":\"TestPassword123!\"}"

Get Current User

curl http://localhost:3000/users/me \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Authentication Flow

  1. A user registers with email, password and name.
  2. The password is hashed with bcrypt.
  3. The user logs in with email and password.
  4. The API returns a JWT token.
  5. Protected routes require:
Authorization: Bearer YOUR_JWT_TOKEN

Security Notes

  • Passwords are never stored as plain text.
  • Passwords are hashed with bcrypt.
  • Strong password validation is applied to registration, password change and password reset.
  • Password reset tokens are not stored as plain text.
  • Password reset tokens are stored as SHA-256 hashes with an expiration timestamp.
  • Reset tokens are cleared after successful password reset.
  • Protected routes require a valid JWT token.
  • Protected routes check the current user status from the database.
  • Secret values are stored in .env.
  • Only .env.example is committed to the repository.

Author

Moj Tabari

Website: https://mtintelligence.ai

GitHub: https://github.com/tabari86

LinkedIn: https://www.linkedin.com/in/mojtaba-tabari

About

User authentication and profile management REST API built with Node.js, Express, MongoDB, JWT and Swagger.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors