This application is a simple authentication server built with Express, using JSON Web Tokens (JWT) for session management and bcrypt for securely storing passwords. Users can register and log in to access protected routes. MySQL is used for storing user data.
Steps for Register Route
Check If the input email is already registered.
- If yes return("User already exists").
- If no Insert the User details in the DB, return("Success")
Steps for Login Route
Check if the input email exists in the DB or not
- If NO return("Invalid email")
- If YES check if the input password is correct for the email or not If NO return("Invalid password").If YES Create the JWT token and send it either in the
Cookie
or in theresponse
VarifyAuthToken
Middleware for Protected Route
- Get the token either from the req.cookie or from the req.headers.
- Valid ate the token using the SECRET_KEY. If it matches return a success response and send the user details. Else send the Invalid Token error.
Technologies Used
1. Express.js: Web framework for handling routes and middleware.
2. bcrypt.js: Library for hashing passwords securely.
3. jsonwebtoken: Library for creating and verifying JWT tokens.
4. mysql2: MySQL client for Node.js with support for Promises.
5. cookie-parser: Middleware for parsing cookies.
Code Breakdown
1. Import Required Libraries
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const cookieParser = require('cookie-parser');
const mysql = require('mysql2/promise');
- express: Provides functions to create routes and handle HTTP requests.
- jsonwebtoken: Used to create and verify JWTs for user sessions.
- bcryptjs: Used for hashing passwords before storing them in the database.
- cookie-parser: Middleware to parse cookies from incoming HTTP requests.
- mysql2/promise: MySQL client with promise support, allowing asynchronous operations.
2. Initialize Express App and Define Constants
const app = express();
const PORT = 3000;
const JWT_SECRET = 'your_jwt_secret_key';
- app: The Express application instance.
- PORT: The port the server will listen on.
- JWT_SECRET: A secret key used to sign JWTs. Replace this with a secure, randomly generated value in production.
3. Database Connection Setup
const db = await mysql.createConnection({
host: 'localhost',
user: 'your_MySql_username',
password: 'your_MySql_password',
database: 'users'
});
- db: The MySQL database connection object.
- mysql.createConnection(): Establishes a connection to the MySQL database using async/await, which is needed for non-blocking queries.
- host: Yout MySql application hostname, If you are running it on localhost, put localhost only, if you have deployed your MySql to a server, use the server hostname with PORT.
- user: Your MySql Username
- password: Your MySql Password
- database: The Database name
4. Middleware Setup
app.use(express.json());
app.use(cookieParser());
- express.json(): Middleware to parse JSON request bodies.
- cookieParser(): Middleware to parse cookies, allowing us to read cookies from req.cookies.
5. Register Route
/register
This route registers a new user by hashing their password and saving it in the database.
app.post('/register', async (req, res) => {
const { name, email, password } = req.body;
try {
// CHECK IF USER ALREADY EXISTS
const [rows] = await db.execute('SELECT * FROM users WHERE email = ?', [email]);
if (rows.length > 0) {
return res.status(400).json({ message: 'User already exists' });
}
// HASH THE PASSWORD
const hashedPassword = await bcrypt.hash(password, 10);
// SAVE THE USER IN THE DATABASE
const result = await db.query('INSERT INTO userDB (name, email, password) VALUES (?, ?, ?)', [user.name, user.email, hashedPassword]);
if(result[0].insertId){
res.status(201).json({ message: 'User registered successfully!', insertId: result[0].insertId });
}
res.status(500).json({message: 'Something went wrong in DB execution'});
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
});
- db.execute(): Executes a query to check if a user with the given email already exists. If they do, return a 400 status.
- bcrypt.hash(password, 10): Hashes the password with a salt rounds value of 10 for security.
- db.execute() (Insert): Saves the user's name, email, and hashed password in the database.
6. Login Route
/login
This route logs in an existing user by checking their credentials and generating a JWT token.
app.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
// CHECK IF USER EXISTS OR NOT
const [rows] = await db.execute('SELECT * FROM users WHERE email = ?', [email]);
const user = rows[0];
if (!user) {
return res.status(400).json({ message: 'User not found' });
}
// CHECK IF INPUT PASSWORD IS VALID FOR INPUT EMAIL
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ message: 'Invalid credentials' });
}
// CREATE THE JWT TOKEN
const token = jwt.sign({ id: user.id, name: user.name, email: user.email }, JWT_SECRET, { expiresIn: '1h' });
// SET THE JWT TOKEN IN THE COOKIE
res.cookie('token', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'Strict',
maxAge: 3600000 // 1 HR EXPIRATION
});
res.json({ message: 'Logged in successfully!' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
});
- bcrypt.compare(password, user.password): Verifies if the hashed password matches the one stored in the database.
- jwt.sign(): Creates a JWT that includes user information (e.g., ID, name, and email). The token expires in 1 hour. jwt.sign() method takes two arguments payload, JWT_SECRET, options(optional)
- res.cookie(): Sets a cookie with the JWT, secured by httpOnly (only accessible by the server) and sameSite settings.
7. JWT Verification Middleware
The verifyAuthToken middleware ensures that only requests with a valid JWT token can access protected routes.
const verifyAuthToken = (req, res, next) => {
const token = req.cookies.token;
if (!token) return res.status(403).json({ message: 'Token is missing.' });
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ message: 'Invalid token.' });
}
};
- req.cookies.token: Extracts the token from cookies.
- jwt.verify(token, JWT_SECRET): Verifies the token using the JWT secret key. If valid, decoded contains the token’s payload, which is assigned to req.user.
- next(): Proceeds to the next middleware if the token is valid.
8. Protected Route - /protected
A sample protected route accessible only to authenticated users. It returns a personalized greeting using the user’s name from the token.
app.get('/protected', verifyAuthToken, (req, res) => {
res.json({ message: `Hello, ${req.user.name}! This is a protected route.` });
});
- verifyAuthToken: Middleware applied to check the user’s authentication status.
- req.user.name: Accesses the user’s name from the decoded JWT payload.
9. Start the Server
The server listens on the defined PORT.
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Full Code
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const cookieParser = require('cookie-parser');
const mysql = require('mysql2/promise');
const app = express();
const PORT = 3000;
const JWT_SECRET = 'your_jwt_secret_key';
// MySQL CONNECTION SETUP
const db = await mysql.createConnection({
host: 'localhost',
user: 'your_MySql_username',
password: 'your_MySql_password',
database: 'users'
});
// MIDDLEWARE
app.use(express.json());
app.use(cookieParser());
// ROUTES
app.post('/register', async (req, res) => {
const { name, email, password } = req.body;
try {
// CHECK IF USER ALREADY EXISTS
const [rows] = await db.execute('SELECT * FROM users WHERE email = ?', [email]);
if (rows.length > 0) {
return res.status(400).json({ message: 'User already exists' });
}
// HASH THE PASSWORD
const hashedPassword = await bcrypt.hash(password, 10);
// SAVE THE USER IN THE DATABASE
const result = await db.query('INSERT INTO userDB (name, email, password) VALUES (?, ?, ?)', [user.name, user.email, hashedPassword]);
if(result[0].insertId){
res.status(201).json({ message: 'User registered successfully!', insertId: result[0].insertId });
}
res.status(500).json({message: 'Something went wrong in DB execution'});
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
});
// LOGIN ROUTE
app.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
// CHECK IF USER EXISTS OR NOT
const [rows] = await db.execute('SELECT * FROM users WHERE email = ?', [email]);
const user = rows[0];
if (!user) {
return res.status(400).json({ message: 'User not found' });
}
// CHECK IF INPUT PASSWORD IS VALID FOR INPUT EMAIL
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ message: 'Invalid credentials' });
}
// CREATE THE JWT TOKEN
const token = jwt.sign({ id: user.id, name: user.name, email: user.email }, JWT_SECRET, { expiresIn: '1h' });
// SET JWT TOKEN IN THE COOKIE
res.cookie('token', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'Strict',
maxAge: 3600000 // 1 HR EXPIRATION TIME
});
res.json({ message: 'Logged in successfully!' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
});
// MIDDLEWARE TO VERIFY THE JWT TOKEN
const verifyAuthToken = (req, res, next) => {
const token = req.cookies.token;
if (!token) return res.status(403).json({ message: 'Token is missing.' });
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ message: 'Invalid token.' });
}
};
// PROTECTED ROUTE
app.get('/protected', verifyAuthToken, (req, res) => {
res.json({ message: `Hello, ${req.user.name}! This is a protected route.` });
});
// START THE SERVER
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Summary
This application:
- Allows user registration by hashing passwords and storing user data in MySQL.
- Supports secure login with JWT authentication.
- Uses cookies to store the JWT on the client side.
- Provides middleware for verifying JWTs before granting access to protected routes.
Top comments (0)