In Blog #26, we hardened browser-facing responses with security headers and Content Security Policy. Now we protect another boundary: state-changing requests. A CSRF attack tries to make an authenticated browser perform an action the user did not intend.
Next.js CSRF protection is architecture-specific. Current Next.js 16 documentation describes built-in request checks for Server Actions, but those checks do not turn 'use server' into authentication, authorization, or validation, and they must not be projected onto arbitrary Route Handlers.
What Is CSRF in Next.js?
Cross-Site Request Forgery is a browser attack in which an untrusted site causes a request to a trusted application where the victim is already authenticated. If the browser attaches a session cookie and the server accepts the mutation without checking intent or request context, the attacker may trigger an account change, purchase, transfer, invitation, or other action without learning the cookie value.
The relevant question is not simply “does this request use POST?” It is: what authenticates the request, which browser contexts send that credential, which framework checks apply to this endpoint, and which authorization rule protects the exact resource?
Authentication, Authorization, CSRF, and Validation
These controls answer different questions. Authentication establishes who is calling. Authorization checks whether that identity may perform the operation on this account, tenant, or record. CSRF protection checks whether a cookie-authenticated browser request has acceptable same-origin intent or proof. Input validation checks the shape and business validity of submitted values. A serious mutation can need all four.

Does Next.js 16 Protect Against CSRF?
For Server Actions, yes—partly and specifically. The current Next.js data-security guide says Server Actions use POST and compare the request Origin with Host or X-Forwarded-Host, aborting when they do not match. The Server Actions configuration reference documents serverActions.allowedOrigins for legitimate additional origins.
That is not a universal CSRF middleware for every endpoint. A Route Handler is an explicit HTTP boundary whose cookie use, callers, methods, CORS behavior, and protections must be reviewed separately. Framework checks also do not prove that a user owns a record or may change a role.
Server Action
Uses the framework action transport and its documented checks. Still authenticate, authorize, and validate inside the action.
Route Handler
Review it as an independent HTTP endpoint. Do not assume Server Action Origin checks automatically apply.
'use server'
export async function updateProject(formData: FormData) {
const session = await requireSession()
const input = UpdateProjectSchema.parse(Object.fromEntries(formData))
await requireProjectPermission(session.user.id, input.projectId, 'update')
return updateProjectRecord(input)
}The action deliberately performs authentication and resource-level authorization. The schema is not an authorization system, and a hidden projectId is untrusted input. Review the mutation architecture in Blog #7: Server Actions and secure form handling in Blog #18: Forms & Validation.
Server Action Origin Protection Behind a Reverse Proxy
A reverse proxy such as Traefik may terminate TLS and forward host information. Next.js uses Host or X-Forwarded-Host during the documented Server Action Origin comparison, so the proxy must set trusted forwarding headers predictably and prevent clients from smuggling arbitrary values. Fix the proxy’s canonical-host behavior instead of broadly allowing origins to silence errors.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
serverActions: {
allowedOrigins: ['app.example.com'],
},
},
}
export default nextConfigVerify the exact syntax against the installed version. Do not add * or every preview domain. The absence of a root package in this repository means no exact Next.js patch or real allowlist can be reported.
Which Requests Need CSRF Protection?
Inventory every state-changing Server Action and every POST, PUT, PATCH, and DELETE handler that can use browser credentials. Account email and password changes, role updates, purchases, transfers, invitations, deletes, subscriptions, and admin commands deserve explicit review. Keep GET, HEAD, and OPTIONS free of side effects.
SameSite, Secure, and HttpOnly Cookies
Cookie-based sessions are an important CSRF context because browsers manage and attach cookies according to request and cookie rules. SameSite influences cross-site sending. Lax commonly preserves ordinary top-level safe-method navigation while limiting many cross-site mutation contexts. Strict is more restrictive and can disrupt legitimate cross-site arrival or authentication flows. None permits cross-site sending and requires Secure, demanding a stronger review of the application’s intended cross-site architecture.
HttpOnly reduces direct JavaScript access to a cookie; it does not stop the browser from sending it. Secure restricts cookie transport to secure contexts; it does not prove request intent. Domain, Path, prefix, and lifetime also influence scope and exposure. See Blog #13: Authentication for the complete session boundary.

When CSRF Tokens Are Appropriate
A token pattern adds proof that a trusted application context obtained a value an attacker cannot submit correctly. OWASP recommends using maintained framework protection first. For stateful applications that need a custom defense, a synchronizer token is stored in server-side session state and submitted separately. For stateless designs, OWASP recommends a signed double-submit cookie bound to session context rather than a naive equality-only cookie.
Tokens must be unpredictable, validated server-side, appropriately bound, compared safely, excluded from URLs, and never logged. A static token, predictable value, or cookie-only check is not a valid defense. Do not add token storage or Redis calls unless a real architecture needs them.
Origin, Referer, and Fetch Metadata
For cookie-authenticated mutations, comparing the request Origin with an exact trusted origin can be a useful defense. When Origin is absent, some architectures use a carefully parsed Referer fallback, but privacy behavior and legitimate clients mean it should not be treated as a universal solution. Compare parsed scheme, host, and port—not an unsafe substring—and understand which target host the proxy makes authoritative.
Fetch Metadata headers such as Sec-Fetch-Site, Sec-Fetch-Mode, and Sec-Fetch-Dest describe browser request context. OWASP documents policies that reject obvious cross-site unsafe requests while permitting legitimate same-origin traffic and handling absent headers with a fallback. Roll out with monitoring and test navigation, OAuth, embedded, and older-client behavior.
Forms and JavaScript Fetch Requests
A secure form combines the chosen CSRF strategy with authentication, resource-level authorization, schema validation, bounded input, safe errors, and rate limiting where abuse or cost justifies it. Hidden fields are user-controlled and never prove ownership or price. JavaScript fetch calls need the same reasoning: JSON is not magic, and credentials, cookies, custom headers, CORS, and caller architecture all affect the result.
Some API designs require a custom request header that ordinary cross-site HTML forms cannot set. That can force a CORS preflight, but the server must maintain a narrow origin policy and reject simple-content-type alternatives if they would bypass the intended contract.
await fetch('/api/account/email', {
method: 'PATCH',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': tokenFromReviewedArchitecture,
},
body: JSON.stringify({ email }),
})CORS, CSP, XSS, and CSRF Are Different
CORS is not CSRF protection. It controls whether browser JavaScript from an origin may access a cross-origin response and governs certain non-simple requests. A state-changing request may still be caused even when an attacker cannot read the response.
CSP is not CSRF protection. The policy from Blog #26 restricts browser resources and script execution. It is valuable defense in depth but does not replace mutation checks. Likewise, CSRF controls do not replace XSS prevention: script executing in the trusted origin may act with the user’s privileges and include application-accessible proof.
Authentication Providers, OAuth, APIs, and Webhooks
No Auth.js, Clerk, or other Next.js authentication provider is present in this publishing repository, so there is no provider behavior to claim. In a real application, follow the provider’s current documentation and reuse its session, OAuth state, PKCE, callback, and CSRF controls. OAuth state protects a login transaction; it is not a universal token for every application form.
Bearer-token APIs have different CSRF characteristics because browsers do not automatically invent and attach an arbitrary Authorization header as they do eligible cookies. Token storage and XSS exposure then become central risks. Webhooks are different again: they usually authenticate the provider with a signature over the raw body, then enforce timestamp, replay, and idempotency rules. Do not apply browser-form tokens blindly to POST /api/webhook. Review custom HTTP boundaries in Blog #10: Route Handlers.
Multi-Instance State, Logging, and Rate Limits
Across App A, B, and C, every replica needs the same canonical-origin rules. If a synchronizer-token design stores required state, the next replica must be able to validate it through a shared session store or a consistent cryptographic design. Do not keep required state only in one container’s memory. Use the scaling principles from Blog #25; do not add Redis solely because this article mentions CSRF.
Log a safe event for rejected origins, invalid proof, suspicious cross-site mutation attempts, and repeated validation failure. Never record session cookies, authorization headers, raw CSRF tokens, passwords, webhook secrets, or sensitive form bodies. Rate limiting from Blog #22 can constrain abuse, but does not establish request intent. Connect safe events to the practices in Blog #24.
Practical Project Review
The repository search found no actual Next.js mutation surface to classify. The table reports discovered evidence without inventing application routes.
| Endpoint/action | Type | Authentication | Authorization | CSRF consideration |
|---|---|---|---|---|
No use server action found | Server Action | Not present | Not present | No implementation to review |
No route.ts mutation found | Route Handler | Not present | Not present | No implementation to review |
/send-mail.php | PHP POST contact handler | Public form | Not applicable to user-owned data | Separate publishing-site abuse review; not a Next.js example |
| No webhook route found | Webhook | Not present | Not present | No provider signature flow to verify |
A safe implementation order is: inventory mutations; verify authentication and authorization; inspect cookie attributes; confirm installed Next.js Server Action behavior; review Route Handlers separately; map Origin and trusted proxy behavior; decide whether tokens are necessary; reuse provider or framework controls; add only justified protection; test accepted and rejected paths; inspect redacted logs; then run the real project’s build and tests.
How to Test CSRF Protection
Test only an application you own or are authorized to assess. In a local or isolated environment, exercise the legitimate same-origin request, missing or invalid proof where applicable, wrong and missing Origin behavior, cross-site simulation, SameSite cookie behavior, unauthenticated and unauthorized callers, and the production proxy path. Use synthetic credentials—never paste real production sessions into commands, fixtures, screenshots, or logs.
Common Next.js CSRF Mistakes
- Assuming Server Actions remove all security work.
- Projecting Server Action checks onto Route Handlers.
- Changing data through GET requests.
- Using
SameSite=Nonewithout reviewing cross-site behavior. - Claiming HttpOnly or Secure prevents CSRF.
- Treating CORS or CSP as a CSRF substitute.
- Using a static, predictable, or URL-based token.
- Logging tokens, cookies, or sensitive form bodies.
- Validating a token without authenticating the session.
- Authenticating without resource-level authorization.
- Trusting Origin without proxy awareness.
- Adding broad
allowedOriginsentries. - Rebuilding provider protections unnecessarily.
- Treating webhooks like browser forms.
- Keeping required state in one replica’s memory.
- Ignoring XSS and client-side CSRF.
Next.js 16 CSRF Protection Checklist
- Keep GET, HEAD, and OPTIONS read-only.
- Authenticate every sensitive mutation.
- Authorize the exact operation and resource.
- Validate every client-controlled value.
- Verify current Server Action behavior for the installed version.
- Review cookie-authenticated Route Handlers independently.
- Choose SameSite deliberately.
- Review HttpOnly, Secure, Domain, Path, prefix, and lifetime.
- Keep Server Action allowed origins narrow.
- Define trusted proxy forwarding behavior.
- Use provider-native auth and OAuth protections.
- Use reviewed token patterns only where needed.
- Never put CSRF proof in a URL or log.
- Use Origin/Referer or Fetch Metadata according to the real compatibility plan.
- Do not use CORS or CSP as substitutes.
- Verify webhook signatures separately.
- Share required validation state across replicas.
- Rate-limit abuse without calling it CSRF protection.
- Log only redacted security events.
- Test critical accepted and denied paths before deployment.
Frequently Asked Questions
What is CSRF in Next.js?
Cross-Site Request Forgery is an attack in which another site causes a browser to send an unwanted authenticated state-changing request to a Next.js application. It matters most when authentication credentials, especially cookies, are attached automatically.
Does Next.js 16 automatically prevent CSRF?
Next.js 16 has built-in protections for Server Actions, including POST-only invocation and Origin comparison with Host or X-Forwarded-Host. Do not assume those controls protect arbitrary Route Handlers or replace authentication, authorization, and validation.
Are Next.js Server Actions protected from CSRF?
Current Next.js documentation describes Origin-to-host comparison and POST-only invocation as built-in Server Action protections. A sensitive action must still authenticate the caller, authorize the exact operation, validate input, and use a correctly configured proxy.
Do Server Actions still need authentication?
Yes. A Server Action is a remotely invokable server entry point. It must validate the current session before sensitive work.
Do Server Actions still need authorization?
Yes. Authentication identifies a caller; authorization decides whether that caller may perform this operation on this resource or tenant.
What is SameSite?
SameSite is a cookie attribute that influences when a browser includes a cookie in cross-site requests. Strict, Lax, and None have different security and compatibility trade-offs.
Should I use SameSite=Lax or Strict?
It depends on the application flow. Strict is more restrictive but may interrupt legitimate cross-site arrivals. Lax often balances navigation and protection, but it is not universally sufficient.
Does HttpOnly prevent CSRF?
No. HttpOnly limits direct JavaScript access to a cookie, but the browser can still attach that cookie to requests.
Does Secure prevent CSRF?
No. Secure limits a cookie to secure transport contexts. It protects transport, not the intent or origin of a state-changing request.
Do I need a CSRF token in Next.js?
It depends on the exact flow, framework behavior, authentication provider, cookie policy, callers, and threat model. Prefer maintained built-in protection; add a reviewed token pattern only where the architecture requires it.
What is Origin validation?
The server compares the request Origin with the application origin it expects. Proxy forwarding and canonical host configuration must be correct, and allowlists should remain narrow.
Is CORS enough to prevent CSRF?
No. CORS controls cross-origin browser access to responses and certain requests; CSRF concerns an unwanted authenticated state change. They are different controls.
Does CSP prevent CSRF?
No. CSP is valuable defense in depth for browser content and script execution, but it does not replace request-level CSRF defenses or authorization.
Are Route Handlers protected like Server Actions?
Do not assume so. Review every cookie-authenticated POST, PUT, PATCH, and DELETE Route Handler as an independent HTTP endpoint and choose protection for its actual callers.
Should GET requests change data?
No. Keep GET, HEAD, and OPTIONS read-only. State changes belong behind mutation methods with authentication, authorization, validation, and the appropriate CSRF strategy.
How should webhooks be protected?
A provider webhook normally uses signature verification, a provider secret, and replay controls rather than browser CSRF tokens. Preserve the signed raw body and follow current provider documentation.
How does CSRF work with multiple Next.js containers?
Origin and proxy rules must be consistent across replicas. If a chosen token design uses server-side state, that state must be shared or otherwise available to every replica that may receive the next request.
Can XSS bypass CSRF protections?
Malicious JavaScript running in the trusted origin can often act with the user privileges and include values available to the application. CSRF controls therefore do not replace XSS prevention, CSP, or output safety.
Current Official References
- Next.js Data Security guide
- Next.js Server Actions configuration
- Next.js
use serverreference - Next.js Route Handlers guide
- OWASP CSRF Prevention Cheat Sheet
- MDN Set-Cookie reference
- MDN Fetch Metadata guide
- MDN secure cookie configuration
Next Steps
Begin with the real application inventory, not a package installation. Separate Server Actions from Route Handlers, document cookies and callers, align Origin and proxy behavior, preserve authentication and authorization, and add a token mechanism only when the selected architecture needs one.
