Loading...
Loading...
> Protect your forms and API endpoints from cross-site request forgery attacks.
CSRF protection prevents attackers from tricking users into performing unwanted actions on your site. NextAuth v5 automatically protects all authentication routes with CSRF tokens.
NextAuth v5 automatically protects all authentication routes with CSRF tokens
1// CSRF protection is automatic for NextAuth routes:2// - /api/auth/signin3// - /api/auth/signout4// - /api/auth/callback/*5// - /api/auth/session67// The middleware in src/middleware.ts handles validation
Retrieve the CSRF token for custom forms
1"use client";23import { getCsrfToken } from "next-auth/react";4import { useEffect, useState } from "react";56export function SecureForm() {7 const [csrfToken, setCsrfToken] = useState<string>("");89 useEffect(() => {10 getCsrfToken().then((token) => {11 if (token) setCsrfToken(token);12 });13 }, []);1415 return (16 <form action="/api/your-endpoint" method="POST">17 <input18 type="hidden"19 name="csrfToken"20 value={csrfToken}21 />22 <input type="text" name="data" />23 <button type="submit">Submit</button>24 </form>25 );26}
Validate CSRF tokens in your API routes
1// src/lib/csrf.ts23import { cookies } from "next/headers";4import { createHash } from "crypto";56export async function validateCsrfToken(token: string): Promise<boolean> {7 const cookieStore = await cookies();8 const sessionToken = cookieStore.get("next-auth.session-token")?.value;910 if (!sessionToken || !token) {11 return false;12 }1314 // Validate token matches session15 const expectedToken = createHash("sha256")16 .update(`${sessionToken}csrf`)17 .digest("hex");1819 return token === expectedToken;20}2122// Usage in API route23// src/app/api/secure-action/route.ts2425import { NextRequest, NextResponse } from "next/server";26import { validateCsrfToken } from "@/lib/csrf";2728export async function POST(request: NextRequest) {29 const body = await request.json();3031 const isValid = await validateCsrfToken(body.csrfToken);3233 if (!isValid) {34 return NextResponse.json(35 { error: "Invalid CSRF token" },36 { status: 403 }37 );38 }3940 // Process secure action41 return NextResponse.json({ success: true });42}
Add origin validation as an additional security layer
1// src/lib/security.ts23import { NextRequest, NextResponse } from "next/server";45export function validateOrigin(request: NextRequest): boolean {6 const origin = request.headers.get("origin");7 const referer = request.headers.get("referer");89 const allowedOrigins = [10 process.env.NEXT_PUBLIC_APP_URL,11 "http://localhost:3000",12 ].filter(Boolean);1314 // Check origin header15 if (origin && !allowedOrigins.includes(origin)) {16 return false;17 }1819 // Check referer header as fallback20 if (!origin && referer) {21 const refererUrl = new URL(referer);22 if (!allowedOrigins.includes(refererUrl.origin)) {23 return false;24 }25 }2627 return true;28}2930// Usage in API route31export async function POST(request: NextRequest) {32 if (!validateOrigin(request)) {33 return NextResponse.json(34 { error: "Invalid request origin" },35 { status: 403 }36 );37 }3839 // Process request40}
Configure secure cookie settings in NextAuth
1// src/lib/auth.ts23import NextAuth from "next-auth";45export const { handlers, auth, signIn, signOut } = NextAuth({6 // ... other config78 cookies: {9 sessionToken: {10 name: "next-auth.session-token",11 options: {12 httpOnly: true,13 sameSite: "lax",14 path: "/",15 secure: process.env.NODE_ENV === "production",16 },17 },18 csrfToken: {19 name: "next-auth.csrf-token",20 options: {21 httpOnly: true,22 sameSite: "lax",23 path: "/",24 secure: process.env.NODE_ENV === "production",25 },26 },27 },28});
Include CSRF tokens in fetch requests
1"use client";23import { getCsrfToken } from "next-auth/react";45async function secureApiCall(data: unknown) {6 const csrfToken = await getCsrfToken();78 const response = await fetch("/api/secure-action", {9 method: "POST",10 headers: {11 "Content-Type": "application/json",12 "X-CSRF-Token": csrfToken || "",13 },14 body: JSON.stringify(data),15 });1617 return response.json();18}1920// Custom hook for secure API calls21import { useState, useCallback } from "react";2223export function useSecureApi() {24 const [loading, setLoading] = useState(false);25 const [error, setError] = useState<string | null>(null);2627 const call = useCallback(async (url: string, data: unknown) => {28 setLoading(true);29 setError(null);3031 try {32 const csrfToken = await getCsrfToken();3334 const response = await fetch(url, {35 method: "POST",36 headers: {37 "Content-Type": "application/json",38 "X-CSRF-Token": csrfToken || "",39 },40 body: JSON.stringify(data),41 });4243 if (!response.ok) {44 throw new Error("Request failed");45 }4647 return await response.json();48 } catch (err) {49 setError(err instanceof Error ? err.message : "Unknown error");50 throw err;51 } finally {52 setLoading(false);53 }54 }, []);5556 return { call, loading, error };57}