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.
Disclaimer: This content is generated by AI.