Authentication and authorization are critical components of any web application, ensuring that only authorized users can access certain resources. In this section, we will explore how to implement robust authentication and authorization mechanisms using the modern Next.js App Router.
Before diving into the implementation, ensure you have the following:
Authentication is the process of verifying a user's identity. In this guide, we will use JSON Web Tokens (JWT) for authentication. JWTs are compact, URL-safe tokens that can be used to verify the authenticity of requests.
Install Required Packages
First, install the necessary packages:
npm install jsonwebtoken bcryptjs next-auth
Create a JWT Utility
Create a utility file lib/jwt.js for generating and verifying tokens:
// lib/jwt.js
import jwt from 'jsonwebtoken';
const secretKey = process.env.JWT_SECRET || 'your_secret_key';
export function generateToken(user) {
return jwt.sign({ userId: user.id, email: user.email }, secretKey, { expiresIn: '1h' });
}
export function verifyToken(token) {
try {
return jwt.verify(token, secretKey);
} catch (err) {
throw new Error('Invalid token');
}
}
Implement Authentication API
Create an API route for user authentication in app/api/auth/route.js:
// app/api/auth/route.js
import bcrypt from 'bcryptjs';
import { generateToken } from '../../lib/jwt';
export async function POST(request) {
const { email, password } = await request.json();
// Dummy user data for demonstration purposes
const user = { id: 1, email: 'user@example.com', password: '$2a$10$...' };
if (!user || !bcrypt.compareSync(password, user.password)) {
return new Response(JSON.stringify({ message: 'Invalid credentials' }), { status: 401 });
}
const token = generateToken(user);
return new Response(JSON.stringify({ token }), { status: 200 });
}
Authorization is the process of granting or denying access to resources based on user permissions. We will use middleware to protect routes.
Create Middleware
Create a middleware file middleware/auth.js:
// middleware/auth.js
import { verifyToken } from '../lib/jwt';
export default async function authMiddleware(request) {
const token = request.headers.get('authorization');
if (!token) {
return new Response(JSON.stringify({ message: 'No token provided' }), { status: 401 });
}
try {
const decoded = verifyToken(token);
request.user = decoded;
return true;
} catch (err) {
return new Response(JSON.stringify({ message: err.message }), { status: 403 });
}
}
Protecting Routes
Use the middleware to protect routes in app/protected/page.js:
// app/protected/page.js
import authMiddleware from '../../middleware/auth';
export default async function ProtectedPage() {
return <h1>Protected Page</h1>;
}
export async function generateMetadata({ params, request }) {
const isAuthorized = await authMiddleware(request);
if (!isAuthorized) {
return { redirect: '/login' };
}
return {};
}
Secure Your Secret Key: Never hard-code your secret key in production. Use environment variables.
// .env.local
JWT_SECRET=your_secret_key
Use HTTPS: Always use HTTPS to encrypt data transmitted between the client and server.
Token Expiry: Set appropriate token expiry times and implement refresh tokens for longer sessions.
Error Handling: Implement proper error handling to avoid exposing sensitive information.
In this guide, we have covered how to implement authentication and authorization in Next.js using JWTs. This setup provides a solid foundation for securing your application and protecting user data. Remember to follow best practices and adapt the implementation to fit the specific needs of your project.