When building web applications, security is one of the most critical aspects you need to focus on. One common way to secure routes and data is by using JWT (JSON Web Token) for authentication. In this post, we’ll walk through implementing JWT authentication in an Express.js app!
⚙️ What is JWT?
JWT (JSON Web Token) is an open standard that defines a compact, self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it’s digitally signed.
- Stateless: Authentication is stored on the client side.
- Compact: JWTs are small and can be sent via URL, POST request, or HTTP headers.
- Secure: Information is signed using a secret or public/private key pair.
🛠️ Step-by-Step Guide to Implement JWT Authentication
Let’s go through the process of securing an Express.js app using JWT. We’ll cover user login, generating tokens, and protecting routes.
1️⃣ Setting Up the Project
First, let’s create an Express.js project and install the necessary dependencies.
# Create a new folder for the project
mkdir express-jwt-auth && cd express-jwt-auth
# Initialize a Node.js project
npm init -y
# Install necessary packages
npm install express jsonwebtoken bcryptjs body-parser
-
express
: For creating the server. -
jsonwebtoken
: To create and verify JWTs. -
bcryptjs
: To hash and compare passwords securely. -
body-parser
: To parse incoming request bodies.
2️⃣ Creating the Express App
Now, let’s create a basic Express server.
// server.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const PORT = 5000;
// Middleware to parse incoming requests
app.use(bodyParser.json());
// Start the server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Run the server:
node server.js
3️⃣ User Registration and Password Hashing
For authentication, we need a way to store user credentials securely. Let’s create a simple in-memory user storage and register users with hashed passwords using bcryptjs
.
// userController.js
const bcrypt = require('bcryptjs');
let users = []; // In-memory user storage
// Register a new user
exports.registerUser = async (req, res) => {
const { username, password } = req.body;
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Store user with hashed password
users.push({ username, password: hashedPassword });
res.status(201).json({ message: 'User registered successfully!' });
};
4️⃣ User Login and JWT Token Generation
When a user logs in, we validate the credentials and generate a JWT token for them. The token is used to authenticate subsequent requests.
// userController.js
const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key'; // Store securely in environment variables
// User login and JWT generation
exports.loginUser = async (req, res) => {
const { username, password } = req.body;
// Find user by username
const user = users.find(u => u.username === username);
if (!user) return res.status(400).json({ message: 'Invalid credentials' });
// Compare password with the stored hash
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) return res.status(400).json({ message: 'Invalid credentials' });
// Generate JWT token
const token = jwt.sign({ username }, secretKey, { expiresIn: '1h' });
res.json({ token });
};
5️⃣ Protecting Routes with JWT Middleware
Now that users can log in and receive JWT tokens, we need to protect certain routes by verifying the token before allowing access.
// authMiddleware.js
const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key';
// Middleware to protect routes
exports.verifyToken = (req, res, next) => {
const token = req.header('Authorization');
if (!token) return res.status(401).json({ message: 'Access Denied' });
try {
// Verify the token
const verified = jwt.verify(token.split(' ')[1], secretKey);
req.user = verified;
next();
} catch (err) {
res.status(400).json({ message: 'Invalid Token' });
}
};
6️⃣ Securing Routes
Now, we can apply the verifyToken
middleware to any route we want to protect.
// server.js
const { registerUser, loginUser } = require('./userController');
const { verifyToken } = require('./authMiddleware');
app.post('/register', registerUser);
app.post('/login', loginUser);
// Protected route
app.get('/dashboard', verifyToken, (req, res) => {
res.json({ message: `Welcome to the dashboard, ${req.user.username}!` });
});
- /register: Allows users to register.
- /login: Logs users in and generates JWT tokens.
- /dashboard: A protected route, accessible only with a valid token.
🔒 Testing the Application
- Register a user:
curl -X POST http://localhost:5000/register -H "Content-Type: application/json" -d '{"username": "user1", "password": "password123"}'
- Login and receive a JWT token:
curl -X POST http://localhost:5000/login -H "Content-Type: application/json" -d '{"username": "user1", "password": "password123"}'
You’ll get a JWT token in response:
{
"token": "your-jwt-token"
}
- Access the protected route:
Use the token to access the /dashboard
route:
curl -X GET http://localhost:5000/dashboard -H "Authorization: Bearer your-jwt-token"
If the token is valid, you’ll receive a welcome message.
🔐 Why JWT?
- Stateless Authentication: JWTs are stored on the client-side, reducing the need for server-side sessions.
- Flexibility: They can be used across different services and technologies, as long as they share the same secret.
- Security: JWTs are signed, making them secure as long as you keep your secret key safe.
🏁 Conclusion
In this tutorial, we’ve implemented a simple JWT authentication system in an Express.js app, showing how to register users, log them in, and protect routes using middleware. JWT makes it easy to add stateless authentication to your Node.js applications, ensuring security and flexibility.
JWTs are a powerful tool for securing your API, but remember to always keep your secret key safe and implement additional security measures like HTTPS, token expiration, and refreshing tokens to protect your app.
📚 Additional Resources:
Happy coding! Let me know if you have any questions or improvements! 😄
Top comments (0)