Creating an authentication and authorization feature in an Express.js RESTful API involves several steps. Here's a step-by-step guide:
Step 1: Set Up a New Express.js Project
- Initialize a New Project:
mkdir project-name
cd project-name
npm init -y
- Install Required Packages:
npm install express mongoose jsonwebtoken bcryptjs
npm install dotenv passport passport-jwt
Step 2: Configure Environment Variables
-
Create a
.env
File:
PORT=3000
MONGODB_URI=mongodb://localhost:27017/auth-db
JWT_SECRET=your_jwt_secret
-
Load Environment Variables:
Create
config.js
to load environment variables:
require('dotenv').config();
module.exports = {
port: process.env.PORT || 3000,
mongodbUri: process.env.MONGODB_URI,
jwtSecret: process.env.JWT_SECRET,
};
Step 3: Set Up Mongoose Models
- Create a Directory Structure:
mkdir -p src/models src/controllers src/routes src/middleware
-
Create User Model:
Create
src/models/User.js
:
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
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();
});
userSchema.methods.matchPassword = async function(enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
const User = mongoose.model('User', userSchema);
module.exports = User;
Step 4: Set Up Controllers
-
Create Auth Controller:
Create
src/controllers/authController.js
:
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const config = require('../../config');
const generateToken = (id) => {
return jwt.sign({ id }, config.jwtSecret, { expiresIn: '1h' });
};
exports.registerUser = async (req, res) => {
const { username, email, password } = req.body;
const userExists = await User.findOne({ email });
if (userExists) {
return res.status(400).json({ message: 'User already exists' });
}
const user = await User.create({ username, email, password });
if (user) {
res.status(201).json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
});
} else {
res.status(400).json({ message: 'Invalid user data' });
}
};
exports.loginUser = async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
});
} else {
res.status(401).json({ message: 'Invalid email or password' });
}
};
exports.getUserProfile = async (req, res) => {
const user = await User.findById(req.user.id);
if (user) {
res.json({
_id: user._id,
username: user.username,
email: user.email,
});
} else {
res.status(404).json({ message: 'User not found' });
}
};
Step 5: Set Up Routes
-
Create Auth Routes:
Create
src/routes/authRoutes.js
:
const express = require('express');
const { registerUser, loginUser, getUserProfile } = require('../controllers/authController');
const { protect } = require('../middleware/authMiddleware');
const router = express.Router();
router.post('/register', registerUser);
router.post('/login', loginUser);
router.get('/profile', protect, getUserProfile);
module.exports = router;
Step 6: Set Up Middleware
-
Create Auth Middleware:
Create
src/middleware/authMiddleware.js
:
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const config = require('../../config');
exports.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, config.jwtSecret);
req.user = await User.findById(decoded.id).select('-password');
next();
} catch (error) {
res.status(401).json({ message: 'Not authorized, token failed' });
}
}
if (!token) {
res.status(401).json({ message: 'Not authorized, no token' });
}
};
Step 7: Set Up the Express Server
-
Create the Server:
Create
src/index.js
:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const config = require('../config');
const authRoutes = require('./routes/authRoutes');
const app = express();
mongoose.connect(config.mongodbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
}).then(() => {
console.log('Connected to MongoDB');
}).catch((err) => {
console.error('Error connecting to MongoDB', err);
});
app.use(bodyParser.json());
app.use('/api/auth', authRoutes);
app.listen(config.port, () => {
console.log(`Server running on http://localhost:${config.port}`);
});
Step 8: Test the API
- Register a User:
POST /api/auth/register
Content-Type: application/json
{
"username": "john",
"email": "john@example.com",
"password": "password"
}
- Login a User:
POST /api/auth/login
Content-Type: application/json
{
"email": "john@example.com",
"password": "password"
}
- Get User Profile (Protected Route):
GET /api/auth/profile
Authorization: Bearer <token>
This guide provides a foundational approach to implementing authentication and authorization in an Express.js RESTful API. You can further expand and customize it based on your application's requirements.
If you enjoy my content and would like to support my work, you can buy me a coffee. Your support is greatly appreciated!
Disclaimer: This content is generated by AI.