A robust and secure authentication backend built with Next.js, TypeScript, and MongoDB. This project provides a complete, production-ready authentication solution with features like JWT-based authentication, refresh tokens, secure password handling, and standardized API responses.
This project is a full-featured authentication backend powered by Next.js API routes. It demonstrates best practices for building secure and scalable authentication systems, including the use of a hybrid token strategy (access and refresh tokens), secure password hashing with Argon2, and safe cookie handling. It also features a standardized API structure for consistent error handling and responses.
- User Registration: Create new user accounts with passwords securely hashed using Argon2, a modern, memory-hard hashing algorithm.
- Email Verification: After registration, users receive a verification email with a secure link. Upon clicking, they are automatically redirected to the login page.
- User Login: Authenticate users and issue JSON Web Tokens (JWT).
- Hybrid Authentication: Implements a robust token-based session management system.
- Short-lived Access Tokens: For authorizing API requests (15-minute expiry).
- Long-lived Refresh Tokens: For obtaining new access tokens without re-login (1-day expiry).
- Secure Cookie Storage: Both access and refresh tokens are stored in
HttpOnlycookies to prevent XSS attacks. - Password Reset Flow: A complete and secure "forgot password" feature that sends a time-limited (1-hour) reset link to the user's email.
- Professional Email Templates: Modern and responsive HTML email templates for a better user experience.
- Protected Routes: Example of a protected
GET /api/auth/meroute that verifies the access token. - Standardized API: Consistent API error and response handling using a reusable pattern.
This project was built with security as a top priority.
- Password Hashing: We use Argon2, the winner of the Password Hashing Competition, which is highly resistant to both GPU cracking attacks and side-channel attacks.
- JWT Security:
- Access tokens are short-lived to minimize the impact of a potential leak.
- Refresh tokens are stored in the database and can be invalidated on logout, providing a mechanism to revoke access.
- Cookie Security:
HttpOnlycookies are used to store tokens, making them inaccessible to client-side JavaScript. This is a critical defense against Cross-Site Scripting (XSS) attacks.Securecookies are used in production to ensure they are only sent over HTTPS. - User Enumeration Prevention: The
/api/auth/forgot-passwordendpoint always returns a success response to prevent attackers from discovering which emails are registered in the system.
To ensure consistency and maintainability, the API routes follow a standard pattern using custom utilities:
asyncHandler: A higher-order function that wraps all API route handlers. It provides a centralizedtry...catchblock to handle any uncaught errors, preventing the server from crashing and ensuring a consistent error response is always sent.ApiError: A custom Error class used for operational errors (e.g., "User not found", "Invalid password"). It includes an HTTP status code, which allows theasyncHandlerto send the correct response.ApiResponse: A custom class that standardizes the structure of all successful JSON responses, ensuring consistency for the client.
The project follows a feature-based structure within the src directory to promote modularity and ease of maintenance.
/src
├── app/
│ ├── api/auth/ # API routes for authentication endpoints (register, login, etc.)
│ ├── favicon.ico # Favicon for the application
│ ├── globals.css # Global CSS styles
│ ├── layout.tsx # Root layout component
│ ├── page.tsx # Home page component
│ ├── forgot-password/ # Page for password reset request
│ ├── home/ # Protected home page after login
│ ├── login/ # Login page
│ ├── register/ # Registration page
│ └── reset-password/ # Page for resetting password
├── components/
│ └── AuthForm.tsx # Reusable authentication form component
├── lib/
│ └── db.ts # MongoDB connection and database utilities
├── models/
│ └── User.ts # Mongoose schema for User model
└── utils/
├── ApiError.ts # Custom error class for API responses
├── ApiResponse.ts # Custom response class for standardized API outputs
├── asyncHandler.ts # Higher-order function for async error handling
├── auth.ts # Utilities for JWT token generation and verification
└── emailTemplates.ts # HTML templates for email notifications
- Node.js (v18 or later)
- pnpm (recommended)
- MongoDB instance (local or cloud-hosted)
-
Clone the repository:
git clone <repository-url> cd <repository-name>
-
Install dependencies:
pnpm install
-
Set up environment variables: Create a file named
.env.localin the root of the project and add the variables from the template below. Never commit this file to version control.# MongoDB Connection String # Connects to your local or cloud-hosted MongoDB database. MONGODB_URI=your_mongodb_connection_string # Base URL of the application # Used for creating absolute links in emails. BASE_URL=http://localhost:3000 # JWT secrets # Use a strong, random string (32+ characters) for each. # You can generate one with: openssl rand -hex 32 JWT_ACCESS_SECRET_KEY=your_super_secret_access_key_32_chars_or_more JWT_REFRESH_SECRET_KEY=your_super_secret_refresh_key_32_chars_or_more # Gmail credentials for sending emails. # For security, it is highly recommended to use a Google App Password # instead of your regular password. EMAIL_USERNAME=your_gmail_username@gmail.com EMAIL_PASSWORD=your_gmail_app_password
-
Run the development server:
pnpm dev
The application will be available at http://localhost:3000.
Below is a detailed list of the available API endpoints, including request examples using curl and expected JSON responses.
Registers a new user account.
Request Example:
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123"
}'Success Response (201):
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": "user_id",
"email": "user@example.com"
}
}
}Authenticates a user and issues access and refresh tokens.
Request Example:
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123"
}'Success Response (200):
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "user_id",
"email": "user@example.com"
}
}
}Note: Tokens are set in HttpOnly cookies.
Logs out the user by invalidating the refresh token.
Request Example:
curl -X POST http://localhost:3000/api/auth/logout \
-H "Cookie: refreshToken=your_refresh_token"Success Response (200):
{
"success": true,
"message": "Logout successful"
}Retrieves the authenticated user's information. Requires a valid access token.
Request Example:
curl -X GET http://localhost:3000/api/auth/me \
-H "Cookie: accessToken=your_access_token"Success Response (200):
{
"success": true,
"data": {
"user": {
"id": "user_id",
"email": "user@example.com"
}
}
}Refreshes the access token using a valid refresh token.
Request Example:
curl -X POST http://localhost:3000/api/auth/refresh \
-H "Cookie: refreshToken=your_refresh_token"Success Response (200):
{
"success": true,
"message": "Token refreshed successfully"
}Note: New access token is set in cookie.
Sends a password reset email to the user.
Request Example:
curl -X POST http://localhost:3000/api/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com"
}'Success Response (200):
{
"success": true,
"message": "If an account with that email exists, a reset link has been sent."
}Resets the user's password using a valid reset token.
Request Example:
curl -X POST http://localhost:3000/api/auth/reset-password \
-H "Content-Type: application/json" \
-d '{
"token": "reset_token_from_email",
"newPassword": "newsecurepassword123"
}'Success Response (200):
{
"success": true,
"message": "Password reset successfully"
}To test the API endpoints, you can use tools like Postman or curl commands. Ensure the development server is running (pnpm dev).
-
Using Postman:
- Import the API endpoints as a collection.
- Set up environment variables for base URL (e.g.,
http://localhost:3000). - For endpoints requiring authentication, include cookies in the request (accessToken or refreshToken).
-
Using curl:
- Refer to the examples in the API Endpoints section above.
- Note that cookies are handled automatically in browsers, but with curl, you may need to manage them manually or use tools like
httpie.
-
Automated Testing:
- Consider using Jest or similar for unit and integration tests.
- Example: Test user registration by sending a POST request and verifying the response.
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Make your changes and ensure tests pass.
- Submit a pull request with a clear description of the changes.
Please adhere to the existing code style and include tests for new features.
- Framework: Next.js
- Language: TypeScript
- Database: MongoDB with Mongoose
- Authentication: JSON Web Tokens (JWT)
- Password Hashing: Argon2
- Email: Nodemailer
- Linting/Formatting: Biome
This project is licensed under the MIT License.