Full-Stack Project Development

Build a complete full-stack application from scratch including frontend, backend, database, authentication, and deployment.

advanced Backend Development 10 hours

Chapter 4: Authentication and Authorization

Chapter 4 of 15

Chapter 4: Authentication and Authorization

4.1 JWT Implementation

JSON Web Tokens (JWT) provide a stateless way to authenticate users and authorize requests.

const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

// Login endpoint
app.post('/api/login', async (req, res) => {
    const { email, password } = req.body;
    
    // Find user
    const user = await User.findOne({ email });
    if (!user) {
        return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    // Verify password
    const isValid = await bcrypt.compare(password, user.password_hash);
    if (!isValid) {
        return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    // Generate token
    const token = jwt.sign(
        { userId: user.id, email: user.email },
        process.env.JWT_SECRET,
        { expiresIn: '24h' }
    );
    
    res.json({ token, user: { id: user.id, email: user.email } });
});

4.2 JWT Middleware

// Authentication middleware
function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];
    
    if (!token) {
        return res.status(401).json({ error: 'Access token required' });
    }
    
    jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
        if (err) {
            return res.status(403).json({ error: 'Invalid or expired token' });
        }
        req.user = user;
        next();
    });
}

// Protected route
app.get('/api/profile', authenticateToken, async (req, res) => {
    const user = await User.findById(req.user.userId);
    res.json(user);
});

4.3 Refresh Tokens

// Generate refresh token
const refreshToken = jwt.sign(
    { userId: user.id },
    process.env.REFRESH_TOKEN_SECRET,
    { expiresIn: '7d' }
);

// Store refresh token
await RefreshToken.create({
    userId: user.id,
    token: refreshToken,
    expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
});

// Refresh endpoint
app.post('/api/refresh', async (req, res) => {
    const { refreshToken } = req.body;
    
    const stored = await RefreshToken.findOne({ token: refreshToken });
    if (!stored || stored.expiresAt < new Date()) {
        return res.status(403).json({ error: 'Invalid refresh token' });
    }
    
    const newAccessToken = jwt.sign(
        { userId: stored.userId },
        process.env.JWT_SECRET,
        { expiresIn: '15m' }
    );
    
    res.json({ token: newAccessToken });
});

4.4 Role-Based Access Control (RBAC)

// Authorization middleware
function authorize(...roles) {
    return (req, res, next) => {
        if (!req.user) {
            return res.status(401).json({ error: 'Unauthorized' });
        }
        
        if (!roles.includes(req.user.role)) {
            return res.status(403).json({ error: 'Forbidden' });
        }
        
        next();
    };
}

// Usage
app.delete('/api/users/:id', 
    authenticateToken, 
    authorize('admin'), 
    deleteUser
);