Building a Secure Authentication API with Node.js, Express, Sequelize, and MySQL
In today's digital landscape, secure authentication mechanisms are critical to protect user data and ensure privacy. Building a robust authentication API using Node.js, Express, Sequelize, and MySQL offers a scalable and efficient solution. Node.js provides a powerful runtime environment, while Express simplifies server setup and routing. Sequelize, an ORM for Node.js, streamlines database interactions with MySQL, facilitating data management. This guide will walk you through creating a secure authentication API, covering user registration, login, and token-based authentication using JSON Web Tokens (JWT).
Project Structure
auth-api/
├── config/
│ └── db.config.js
├── controllers/
│ └── auth.controller.js
├── models/
│ ├── index.js
│ └── user.model.js
├── routes/
│ └── auth.routes.js
├── tests/
│ └── auth.tests.js
├── .env
├── .gitignore
├── index.js
├── package.json
└── README.md
Step-by-Step Guide
Step 1: Initialize the Project
Create the Project Directory:
mkdir auth-api cd auth-api
Initialize a Node.js Project:
npm init -y
Install Dependencies:
npm install express sequelize mysql2 bcryptjs jsonwebtoken dotenv
Step 2: Set Up Configuration
Create the
config
Directory:mkdir config
Create
db.config.js
in theconfig
Directory://code// config/db.config.js module.exports = { HOST: process.env.DB_HOST, USER: process.env.DB_USER, PASSWORD: process.env.DB_PASSWORD, DB: process.env.DB_NAME, dialect: "mysql", pool: { max: 5, min: 0, acquire: 30000, idle: 10000, }, };
Step 3: Set Up Models
Create the
models
Directory:mkdir models
Create
index.js
in themodels
Directory:const { Sequelize, DataTypes } = require('sequelize'); require('dotenv').config(); const dbConfig = { HOST: process.env.DB_HOST, USER: process.env.DB_USER, PASSWORD: process.env.DB_PASSWORD, DB: process.env.DB_NAME, dialect: "mysql", pool: { max: 5, min: 0, acquire: 30000, idle: 10000 } }; const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, { host: dbConfig.HOST, dialect: dbConfig.dialect, pool: dbConfig.pool, }); const db = {}; db.Sequelize = Sequelize; db.sequelize = sequelize; db.user = require('./user.model.js')(sequelize, DataTypes); module.exports = db;
Create
user.model.js
in themodels
Directory:module.exports = (sequelize, DataTypes) => { const User = sequelize.define('user', { username: { type: DataTypes.STRING, allowNull: false, unique: true }, email: { type: DataTypes.STRING, allowNull: false, unique: true }, password: { type: DataTypes.STRING, allowNull: false } }); return User; };
Step 4: Set Up Controllers
Create the
controllers
Directory:mkdir controllers
Create
auth.controller.js
in thecontrollers
Directory://code// controllers/auth.controller.js const db = require('../models'); const User = db.user; const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); // Signup function exports.signup = async (req, res) => { try { const { username, email, password } = req.body; // Check if the username or email already exists const existingUser = await User.findOne({ where: { email } }); if (existingUser) { return res.status(400).send({ message: "Email is already registered." }); } // Hash password const hashedPassword = bcrypt.hashSync(password, 8); // Save user to database const user = await User.create({ username, email, password: hashedPassword }); res.status(201).send({ message: "User registered successfully!" }); } catch (err) { res.status(500).send({ message: err.message }); } }; // Login function exports.login = async (req, res) => { try { const { email, password } = req.body; // Find user by email const user = await User.findOne({ where: { email } }); if (!user) { return res.status(404).send({ message: "User not found." }); } // Check password const passwordIsValid = bcrypt.compareSync(password, user.password); if (!passwordIsValid) { return res.status(401).send({ accessToken: null, message: "Invalid Password!" }); } // Sign JWT token const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: 86400 // 24 hours }); res.status(200).send({ id: user.id, username: user.username, email: user.email, accessToken: token }); } catch (err) { res.status(500).send({ message: err.message }); } }; exports.AllSignUpUser= async(req,res)=>{ try { const users = await User.findAll(); res.status(200).send({ users }); } catch (err) { res.status(500).send({ message: err.message }); } }
Step 5: Set Up Routes
Create the
routes
Directory:mkdir routes
Create
auth.routes.js
in theroutes
Directory:const express = require('express'); const router = express.Router(); const authController = require('../controller/auth.controller'); router.get('/', function (req, res) { res.send("you are enter at auth.routes.js ") }); router.post('/signup', authController.signup); router.post('/login', authController.login); router.get('/allsignupusers',authController.AllSignUpUser) module.exports = router; // /api/auth/signup
Step 6: Set Up the Main Application
Create
index.js
in the Root Directory://code// index.js const express = require("express"); const bodyParser = require("body-parser"); const cors = require("cors"); const db = require("./models"); const authRoutes = require("./routes/auth.routes"); const app = express(); app.use(cors()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use("/api/auth", authRoutes); db.sequelize.sync() .then(() => { console.log("Database synced successfully."); }) .catch((err) => { console.log("Failed to sync database: " + err.message); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); });
Step 7: Set Up Environment Variables
Create
.env
in the Root Directory:DB_HOST=your_database_host DB_USER=your_database_username DB_PASSWORD=your_database_password DB_NAME=your_database_name JWT_SECRET=your_secret_key
Step 8: Set Up Git Ignore
Create
.gitignore
in the Root Directory:node_modules/ .env
Step 9: Run the Application
Start the Server:
node index.js
Your authentication API should now be running at
http://localhost:3000
.
How to Check API Functionality Using Postman
Once You have your authentication API up and running, you can use Postman to test its endpoints and ensure everything works correctly. Follow these steps to check the API functionality using Postman.
Prerequisites
Ensure your server is running by executing
node index.js
in your project directory.Download and install Postman if you haven't already.
Testing the API Endpoints
1. Test the Sign Up Endpoint
Endpoint:POST /api/auth/signup
Open Postman and create a new request.
Set the request type to
POST
.Enter the UR****L:
http://localhost:3000/api/auth/signup
Go to the
Body
tab and selectraw
.Set the format to
JSON
.Enter the following JSON data:
{ "username": "testuser", "email": "testuser@example.com", "password": "password123" }
Click
Send
.
Expected Response:
Status:
201 Created
Body:
{ "message": "User created successfully!", "user": { "id": 1, "username": "testuser", "email": "testuser@example.com", "password": "$2a$10$..." } }
2. Test the Login Endpoint
Endpoint:POST /api/auth/login
Open Postman and create a new request.
Set the request type to
POST
.Enter the URL:
http://localhost:3000/api/auth/login
Go to the
Body
tab and selectraw
.Set the format to
JSON
.Enter the following JSON data:
{ "email": "testuser@example.com", "password": "password123" }
Click
Send
.
Expected Response:
Status:
200 OK
Body:
{ "message": "Login successful", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }
3. Test an Admin Functionality (Optional)
For admin functionalities, you need to implement specific routes and permissions. Below is an example of how to test fetching all users (assuming you have an admin route set up).
Endpoint:GET /api/auth/users
(Assuming this endpoint lists all users and is protected)
Open Postman and create a new request.
Set the request type to
GET
.Enter the URL:
http://localhost:3000/api/auth/users
Go to the
Headers
tab.Add a new header:
Key:
Authorization
Value:
Bearer YOUR_JWT_TOKEN
(ReplaceYOUR_JWT_TOKEN
with the token received from the login endpoint)
Click
Send
.
Expected Response:
Status:
200 OK
Body:
[ { "id": 1, "username": "testuser", "email": "testuser@example.com" }, // other users... ]
Summary of Postman Testing
Sign Up a New User:
Use the
POST /api/auth/signup
endpoint.Verify the response indicates a successful user creation.
Log In with the New User:
Use the
POST /api/auth/login
endpoint.Verify the response returns a JWT token.
Access Protected Routes:
Use the
GET /api/auth/users
endpoint (or any other protected route).Include the JWT token in the
Authorization
header.Verify you receive the expected data for authenticated requests.
By following these steps, you can thoroughly test your authentication API using Postman, ensuring all endpoints function as expected and your API provides the intended security and usability.
To dive into advanced unit testing techniques, navigate to the next article by click here.
Conclusion
This step-by-step guide has walked you through creating a secure authentication API with Node.js, Express, Sequelize, and MySQL. Each section covers the creation and setup of necessary folders and files, ensuring a clear understanding of the project's structure and workflow. This setup will allow you to build, run, and extend the authentication functionality as needed.
You can check out the full project on GitHub: Github Account :- Dhruv9099
Feel free to leave feedback or ask questions in the comments. Your input is valuable and helps improve future projects!
Subscribe to my newsletter
Read articles from Dhruvkumar Maisuria directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Dhruvkumar Maisuria
Dhruvkumar Maisuria
About Me As a dedicated tech enthusiast with a passion for continuous learning, I possess a robust background in software development and network engineering. My journey in the tech world is marked by an insatiable curiosity and a drive to solve complex problems through innovative solutions. I have honed my skills across a diverse array of technologies, including Python, AWS, SQL, and Golang, and have a strong foundation in web development, API testing, and cloud computing. My hands-on experience ranges from creating sophisticated applications to optimizing network performance, underscored by a commitment to excellence and a meticulous attention to detail. In addition to my technical prowess, I am an avid advocate for knowledge sharing, regularly contributing to the tech community through blogs and open-source projects. My proactive approach to professional development is demonstrated by my ongoing exploration of advanced concepts in programming and networking, ensuring that I stay at the forefront of industry trends. My professional journey is a testament to my adaptability and eagerness to embrace new challenges, making me a valuable asset in any dynamic, forward-thinking team. Whether working on a collaborative project or independently, I bring a blend of analytical thinking, creative problem-solving, and a deep-seated passion for technology to every endeavor.