Authenticating an API is crucial for ensuring security, controlling access, and maintaining data integrity. By verifying the identity of users or systems accessing the API, authentication helps prevent unauthorized access, data breaches, and malicious activity. It also enables the enforcement of permissions and roles, ensuring that only authorized entities can interact with specific endpoints or resources. Proper API authentication safeguards sensitive data, enhances trust in the system, and supports compliance with industry standards and regulations.
To add JWT (JSON Web Token) authentication to your Node.js API, follow these steps:
1. Install Required Packages
You’ll need to install a few npm packages for JWT and password hashing. Here are the key ones:
$ npm install jsonwebtoken bcryptjs express body-parser
jsonwebtoken
: To sign and verify tokens.bcryptjs
: To hash passwords.express
: For creating the API.body-parser
: To parse JSON request bodies.
2. Create the API Structure
Create a basic folder structure:
/my-app
/config
db.js # For database connection
/controllers
authController.js # For handling authentication logic
/models
User.js # User model
/routes
authRoutes.js # Routes for authentication
/middleware
auth.js # Middleware for protecting routes
server.js # Entry point of the application
3. Create User Model
For simplicity, let’s assume you’re using MongoDB with Mongoose for user storage.
// /models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// Hash password before saving user
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
// Compare entered password with stored hash
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
module.exports = mongoose.model('User', userSchema);
4. Create Authentication Controller
In this controller, you’ll define methods for user registration, login, and generating JWT tokens.
// /controllers/authController.js
const User = require('../models/User');
const jwt = require('jsonwebtoken');
// Register a new user
exports.register = async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.create({ username, password });
const token = generateToken(user._id);
res.status(201).json({ token });
} catch (error) {
res.status(400).json({ error: 'User registration failed' });
}
};
// Login an existing user
exports.login = async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user || !(await user.matchPassword(password))) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = generateToken(user._id);
res.json({ token });
} catch (error) {
res.status(500).json({ error: 'Login failed' });
}
};
// Generate JWT Token
const generateToken = (id) => {
return jwt.sign({ id }, 'your_jwt_secret', { expiresIn: '1h' });
};
5. Create Authentication Routes
Now, set up the routes for registration and login:
// /routes/authRoutes.js
const express = require('express');
const { register, login } = require('../controllers/authController');
const router = express.Router();
router.post('/register', register);
router.post('/login', login);
module.exports = router;
6. Create Middleware to Protect Routes
You’ll need middleware to verify the JWT for protected routes:
// /middleware/auth.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const protect = async (req, res, next) => {
let token;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try {
token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, 'your_jwt_secret');
// Attach user to request
req.user = await User.findById(decoded.id).select('-password');
next();
} catch (error) {
res.status(401).json({ error: 'Not authorized, token failed' });
}
}
if (!token) {
res.status(401).json({ error: 'Not authorized, no token' });
}
};
module.exports = protect;
7. Protect Your Routes
Now that the authentication logic is ready, you can protect any route by using the protect
middleware:
// /routes/privateRoutes.js
const express = require('express');
const protect = require('../middleware/auth');
const router = express.Router();
router.get('/profile', protect, (req, res) => {
res.json({ user: req.user });
});
module.exports = router;
8. Set Up the Server
Finally, tie everything together in your server.js
file:
// server.js
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const authRoutes = require('./routes/authRoutes');
const privateRoutes = require('./routes/privateRoutes');
const app = express();
// Database connection
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
app.use(bodyParser.json());
app.use('/api/auth', authRoutes);
app.use('/api/private', privateRoutes);
app.listen(5000, () => {
console.log('Server running on http://localhost:5000');
});
9. Testing the API
- Register: Send a
POST
request to/api/auth/register
with a JSON body{ "username": "yourusername", "password": "yourpassword" }
. - Login: Send a
POST
request to/api/auth/login
with a JSON body{ "username": "yourusername", "password": "yourpassword" }
. - Access Protected Route: Use the token received from login or register and send it in the
Authorization
header (asBearer <token>
) to access protected routes like/api/private/profile
.
Conclusion
By following these steps, you can successfully add JWT authentication to your Node.js API, ensuring secure user authentication and access to protected routes.
Leave a Reply