API Authentication
Authentication is crucial for protecting your API routes and user data. Next.js provides several ways to implement authentication, from simple token-based systems to robust solutions like NextAuth.js.
Think of authentication as a bouncer at a club. It checks IDs, verifies credentials, and only lets authorized users in. Your API needs similar protection to prevent unauthorized access.
Token-Based Authentication
The most common approach is using JWT (JSON Web Tokens). Here's how to implement it:
// app/api/auth/login/route.js
import { NextResponse } from 'next/server';
import jwt from 'jsonwebtoken';
export async function POST(request) {
const { email, password } = await request.json();
const user = await authenticateUser(email, password);
if (!user) {
return NextResponse.json(
{ error: 'Invalid credentials' },
{ status: 401 }
);
}
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
return NextResponse.json({ token, user });
}
This creates a login endpoint that returns a JWT token. The client can store this token and send it with subsequent requests.
Verifying Tokens
You need to verify tokens on protected routes. Create a helper function to extract and validate the token:
// app/api/users/route.js
import { NextResponse } from 'next/server';
import jwt from 'jsonwebtoken';
function verifyAuth(request) {
const authHeader = request.headers.get('authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return null;
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
return decoded;
} catch (error) {
return null;
}
}
export async function GET(request) {
const user = verifyAuth(request);
if (!user) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const users = await getUsers();
return NextResponse.json(users);
}
Using NextAuth.js
For more complex authentication needs, consider NextAuth.js. It provides a complete authentication solution with multiple providers.
// app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth';
import GithubProvider from 'next-auth/providers/github';
import GoogleProvider from 'next-auth/providers/google';
const handler = NextAuth({
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
});
export { handler as GET, handler as POST };
NextAuth.js handles the entire authentication flow, including sign-in, sign-out, and session management.
Best Practices
Follow these best practices for secure authentication:
Use HTTPS: Always use HTTPS in production to prevent token interception.
Store tokens securely: Use httpOnly cookies or secure storage mechanisms.
Implement refresh tokens: Use short-lived access tokens with refresh tokens for better security.
Validate on the server: Never trust client-side validation alone. Always verify tokens on the server.
Authentication is a critical security layer. Take it seriously and test your implementation thoroughly.