Creating Secure Password Flows With Node.js And MySQL
- Published on
Creating Secure Password Flows With Node.js And MySQL 🔐
Node.js, a popular JavaScript runtime environment, and MySQL, a widely used open-source relational database management system (RDBMS), are powerful tools for building web applications. However, handling user authentication and password management securely requires careful consideration of best practices and implementation techniques.
This guide will walk you through the process of creating secure password flows using Node.js, Express.js (a popular web framework for Node.js), and MySQL. It will cover essential aspects such as user registration, login, password hashing, and password reset.
Prerequisites 💻
Before you begin, ensure you have the following prerequisites:
- Node.js and npm installed on your system
- Basic understanding of Node.js, Express.js, and MySQL
- Familiarity with HTML, CSS, and JavaScript
Project Setup 🏗️
- Create a Node.js Project:
npx create-express-app my-secure-app
Install Necessary Dependencies:
npm install bcryptjs express-session mysql2
##Configure MySQL Connection: Create a .env
file to store your MySQL connection details:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password
DB_NAME=secure_app_db
Create Database and Tables:
Create the required tables in your MySQL database:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
password_reset_token VARCHAR(255)
);
User Registration ✍️ Create User Registration Route:
- Create a route to handle user registration requests:
app.post('/register', async (req, res) => {
const { email, password } = req.body;
// Hash the password using bcryptjs
const hashedPassword = await bcrypt.hash(password, 10);
// Insert the user into the database
await db.query('INSERT INTO users (email, password
User Registration ✍️
- Create User Registration Route: Create a route to handle user registration requests:
javascript
app.post('/register', async (req, res) => {
const { email, password } = req.body;
// Hash the password using bcryptjs
const hashedPassword = await bcrypt.hash(password, 10);
// Insert the user into the database
await db.query('INSERT INTO users (email, password) VALUES (?, ?)', [email, hashedPassword]);
// Send a success response
res.status(201).send({ message: 'User registered successfully' });
});
- Password Hashing:
Password hashing is a crucial security measure that prevents passwords from being stored in plain text. bcryptjs, a popular password hashing library for Node.js, is used in this example to generate a secure hash of the user's password. The hashed password is stored in the database, and the original password is never stored or transmitted.
User Login 🔑
- Create User Login Route:
Create a route to handle user login requests:
javascript
app.post('/login', async (req) => {
const { email, password } = req.body;
// Retrieve the user from the database based on the provided email
const user = await db.query('SELECT * FROM users WHERE email = ?', [email]);
if (!user || !user.length) {
return res.status(401).send({ message: 'Invalid email or password' });
}
// Compare the provided password with the stored hashed password
const isPasswordValid = await bcrypt.compare(password, user[0].password);
if (!isPasswordValid) {
return res.status(401).send({ message: 'Invalid email or password' });
}
// Create a session and store the user's ID
req.session.userId = user[0].id;
// Send a success response
res.send({ message: 'Login successful' });
});
- Password Comparison: When a user attempts to log in, the provided password is compared with the stored hashed password using bcryptjs's
compare()
method. This method securely compares the two passwords without revealing the original password. If the passwords match, the user is successfully logged in.
Password Reset 🔄
- Create Password Reset Request Route:
Create a route to handle password reset requests:
javascript
app.post('/request-password-reset', async (req) => {
const { email } = req.body;
// Generate a random password reset token
const resetToken = generateToken();
// Set the password reset token for the user
await db.query('UPDATE users SET password_reset_token = ? WHERE email = ?', [resetToken, email]);
// Send an email with the password reset link
sendPasswordResetEmail(email, resetToken);
// Send a success response
res.send({ message: 'Password reset request sent successfully' });
});
- Password Reset Route: Create a route to handle password resets:
app.post('/reset-password', async (req) => {
const { token, password } = req.body;
// Verify the password reset token
const user = await db.query('SELECT * FROM users WHERE password_reset_token = ?', [token]);
if (!user || !user.length) {
return res.status(401).send({ message: 'Invalid password reset token' });
}
// Hash the new password
const hashedPassword = await bcrypt.hash(password, 10);
// Update the user's password and clear the reset token
await db.query('UPDATE users SET password = ?, password_reset_token = NULL WHERE id = ?', [hashedPassword, user[0].id]);
// Send a success response
res.send({ message: 'Password reset successful' });
});
Additional Considerations 🔐
Session Management: Express.js's
express-session
middleware is used in this example to manage user sessions. Sessions allow you to keep track of a user's logged-in state across requests.Token-based Authentication: For more advanced security, consider implementing token-based authentication using JSON Web Tokens (JWTs).
Email Security: Use secure email practices