new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Next.js · Guides · all subjects

authentication/server-actions

56 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Server Actions execute on the server and handle form submissions

React Server Actions are Server Functions that execute on the server. They can be called in both Server and Client Components to handle form submissions. Always verify authentication and authorization inside each Server Action, even if the form is only rendered on an authenticated page.

Form action attribute invokes Server Actions with FormData

React extends the HTML form element to allow Server Actions to be invoked with the action attribute. When used in a form, the function automatically receives the FormData object. You can extract data using native FormData methods like formData.get('fieldName').

Object.fromEntries() with FormData contains extra properties prefixed with $ACTION_

When working with forms that have multiple fields, use JavaScript's Object.fromEntries() method. For example: const rawFormData = Object.fromEntries(formData). Note that this object will contain extra properties prefixed with $ACTION_.

Pass additional arguments to Server Functions using bind()

Outside of form fields, you can pass additional arguments to a Server Function using the JavaScript bind() method. For example, to pass the userId argument: const updateUserWithId = updateUser.bind(null, userId). The Server Function will receive the userId as an additional argument before formData. An alternative is to pass arguments as hidden input fields, but the value will be part of the rendered HTML and not encoded.

Server Action signature with bind includes bound arguments before formData

When using bind() to pass additional arguments to a Server Action, the function signature receives the bound arguments first, followed by formData. For example: export async function updateUser(userId: string, formData: FormData) {}

bind() works in both Server and Client Components

The bind() method works in both Server and Client Components and supports progressive enhancement.

useOptimistic hook updates UI before Server Function completes

You can use the React useOptimistic hook to optimistically update the UI before the Server Function finishes executing, rather than waiting for the response. The hook receives the initial state and a reducer function that produces the optimistic state.

Nested form elements can call Server Actions with formAction prop

You can call Server Actions in elements nested inside a form such as button, input type='submit', and input type='image'. These elements accept the formAction prop or event handlers. This is useful for calling multiple Server Actions within a single form, such as different actions for saving a draft versus publishing.

Programmatic form submission using requestSubmit()

You can trigger a form submission programmatically using the HTMLFormElement.requestSubmit() method. For example, you can listen for the onKeyDown event to submit a form when the user presses Ctrl+Enter or Cmd+Enter, then call e.currentTarget.form?.requestSubmit() to trigger submission of the nearest form ancestor.

useOptimistic signature with TypeScript generics

In TypeScript, useOptimistic can be typed with generics: useOptimistic<State[], ActionType>(initialState, (state, action) => newState). The first generic parameter is the state type, and the second is the action type passed to the update function.

Server Action form example with authentication check

Example of a Server Action that validates authentication before processing form data: ```tsx import { auth } from '@/lib/auth' export default function Page() { async function createInvoice(formData: FormData) { 'use server' const session = await auth() if (!session?.user) { throw new Error('Unauthorized') } const rawFormData = { customerId: formData.get('customerId'), amount: formData.get('amount'), status: formData.get('status'), } // mutate data // revalidate the cache } return <form action={createInvoice}>...</form> } ``` This example shows how to check authentication and extract form data using formData.get().

useOptimistic example with optimistic message updates

Example of using useOptimistic to update the UI before Server Action completes: ```tsx 'use client' import { useOptimistic } from 'react' import { send } from './actions' type Message = { message: string } export function Thread({ messages }: { messages: Message[] }) { const [optimisticMessages, addOptimisticMessage] = useOptimistic< Message[], string >(messages, (state, newMessage) => [...state, { message: newMessage }]) const formAction = async (formData: FormData) => { const message = formData.get('message') as string addOptimisticMessage(message) await send(message) } return ( <div> {optimisticMessages.map((m, i) => ( <div key={i}>{m.message}</div> ))} <form action={formAction}> <input type="text" name="message" /> <button type="submit">Send</button> </form> </div> ) } ``` This shows optimistic updates where the new message appears immediately in the UI before the Server Action completes.

bind() example for passing userId to Server Action

Example of using bind() to pass additional arguments to a Server Action: ```tsx 'use client' import { updateUser } from './actions' export function UserProfile({ userId }: { userId: string }) { const updateUserWithId = updateUser.bind(null, userId) return ( <form action={updateUserWithId}> <input type="text" name="name" /> <button type="submit">Update User Name</button> </form> ) } ``` The Server Action signature becomes: export async function updateUser(userId: string, formData: FormData) {}

Programmatic form submission with keyboard shortcut

Example of triggering form submission programmatically when user presses Ctrl+Enter or Cmd+Enter: ```tsx 'use client' export function Entry() { const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { if ( (e.ctrlKey || e.metaKey) && (e.key === 'Enter' || e.key === 'NumpadEnter') ) { e.preventDefault() e.currentTarget.form?.requestSubmit() } } return ( <div> <textarea name="entry" rows={20} required onKeyDown={handleKeyDown} /> </div> ) } ``` This calls requestSubmit() on the nearest form ancestor to trigger the Server Action.

useOffline experimental config keeps Server Actions pending during connectivity loss

With the experimental useOffline config enabled, a Server Action interrupted by a connectivity drop stays pending and completes when the network returns, so a user does not lose their submission.

Server Actions with Multi-Zones allowedOrigins configuration

When using Server Actions with Multi-Zones, you must explicitly allow the user-facing origin since your user-facing domain may serve multiple applications. In next.config.js, add experimental.serverActions.allowedOrigins with your production domain: const nextConfig = { experimental: { serverActions: { allowedOrigins: ['your-production-domain.com'] } } }

Use Server Actions for form submissions

Server Actions should be used to handle form submissions, server-side validation, and error handling in Next.js applications.

What is a Server Action

A Server Action is a React Server Function invoked through React's action mechanisms, such as <form action>, <button formAction>, or a client-side transition. You create one by adding the 'use server' directive, then invoke it from a form, or from an event handler or useEffect wrapped in startTransition.

Server Action vs Route Handler

A Server Action is a React Server Function invoked through action mechanisms like <form action>, <button formAction>, or useTransition. A Route Handler is used for non-mutation requests and can be invoked from client code for parallel work when Server Actions dispatch sequentially. Server Actions are specifically for mutations and automatically serialize responses to include both returned data and re-rendered UI, while Route Handlers are traditional HTTP endpoints.

Sequential dispatch of Server Actions on client

Next.js dispatches Server Actions one at a time per client. If a user triggers three actions in quick succession, the second waits for the first to finish, then the third waits for the second. This keeps the re-rendered server tree consistent with the action result that produced it. This is a property of the client dispatcher, not of Server Functions in general. Server-side, an action runs in its own request and can do anything an async function can do.

Parallel execution in Server Actions

Do not rely on Promise.all to parallelize Server Actions from the client due to sequential dispatch. If you need parallel work, do it inside a single Server Action, fetch in parallel from a Server Component, or use a Route Handler for non-mutation requests.

Single response carries data and UI

When a Server Action triggers an immediate revalidation, Next.js runs the action and re-renders the current route server-side within one HTTP request. The response contains both the action's return value (consumed by useActionState or the awaited promise) and a newly rendered RSC Payload for the current route, which the client commits as a seeded navigation. The application code does not need a follow-up fetch to see the updated UI.

Server Action response includes re-render when

A re-render is included in the same response when the action does any of these: calls updateTag or revalidatePath to immediately invalidate cached data; calls refresh to refetch the current route's RSC Payload; mutates cookies through cookies() where setting or deleting a cookie automatically re-renders the current page; or calls redirect which navigates the router and streams the destination's RSC Payload.

Server Action security framework protections

Next.js enforces framework-level protections for Server Actions: CSRF check comparing request Origin to Host (or X-Forwarded-Host), with mismatches rejected; Body size limit of 1MB by default; Encrypted action IDs and dead code elimination where action references are encrypted at build time and unused Server Functions are stripped from client bundles; Closure variable encryption where variables captured by inline actions are encrypted before being sent to the client.

Server Action application-level security requirements

Framework protections are not a substitute for application-level checks. Inside every action: Authenticate and authorize (render-time gating is not a security boundary because requests can be sent without going through the UI); Validate inputs treating FormData, query parameters, and headers as untrusted; Constrain return values since they are serialized to the client and should be shaped to what the UI renders, not raw database records.

Safe Server Action pattern for mutations

A client should send only a reference (typically an ID) plus the user's change to a Server Action, not the full item object. The server should re-read the rest from a trusted source using the session, verify ownership, and perform authorization checks. Schema validation only checks the shape of the input; a well-formed object can still refer to a row the caller does not own.

updateTag vs revalidateTag vs revalidatePath vs refresh

updateTag: immediate expiration of a tag, next read waits for fresh data, use for read-your-own-writes. revalidateTag: stale-while-revalidate refresh with cache-life profile, subsequent reads get stale value while fresh fetch happens in background, action's re-render does not wait for new data. revalidatePath: invalidate by URL path, use when one route is affected. refresh: refetch current route's RSC Payload without invalidating cached data, use when view depends on state outside cache that action changed.

revalidateTag stale-while-revalidate skips immediate re-render

revalidateTag with a stale-while-revalidate profile intentionally skips the immediate re-render in the action response. When updateTag, revalidatePath, or refresh runs, Next.js re-renders the current route server-side and includes a newly rendered RSC Payload in the action response. revalidateTag marks the tag for background refresh and does not include a re-render in the action response.

Server Action revalidation does not throw

Unlike redirect, updateTag, revalidatePath, and refresh do not throw, so an action can call them and still return a value to the caller. redirect throws a control-flow exception, so code after it does not run. Place revalidation calls before redirect if the destination needs fresh data.

Server Action configuration in next.config.js

The serverActions option in next.config.js controls framework-level behavior with experimental.serverActions.allowedOrigins (array of proxy/CDN domains) and experimental.serverActions.bodySizeLimit (default 1MB).

Closure encryption key for Server Actions

For closure variable encryption in Server Actions, set NEXT_SERVER_ACTIONS_ENCRYPTION_KEY in the deployment environment. For multi-instance and self-hosted deployments, set this to a stable key shared across instances so closure variables remain decryptable everywhere.

Server Action IDs and deployment

Each Server Action is identified by an action ID that is part of build artifacts. New deployments typically generate new IDs (Next.js rotates them at most every 14 days, even when source is unchanged), so a client running the previous build may invoke an action ID that no longer exists, surfacing a 'Failed to find Server Action' error.

Server Action deployment best practices

To minimize disruption when deploying Server Actions: Prefer rolling deployments over abrupt cutovers when active users are likely mid-mutation. Keep NEXT_SERVER_ACTIONS_ENCRYPTION_KEY stable across instances so action references remain decryptable everywhere. Surface the 'Failed to find Server Action' error as a retry path in the UI rather than a hard failure, so a refresh recovers the user.

Server Action security - build time encryption

At build time, the 'use server' directive tells the compiler to swap the function's implementation in client bundles for a reference (an action ID plus a dispatcher) that POSTs back to the server. The implementation stays on the server, but the route is reachable to anyone who can send the same POST. Treat every action as an untrusted entry point.

Example Server Action with revalidation and security

Example showing a Server Action that creates a post: ```ts 'use server' import { revalidatePath } from 'next/cache' import { auth } from '@/lib/auth' import { db } from '@/lib/db' export async function createPost(formData: FormData) { const session = await auth() if (!session?.user) throw new Error('Unauthorized') await db.post.create({ data: { title: String(formData.get('title')), authorId: session.user.id, }, }) revalidatePath('/posts') } ``` This shows authentication check, input validation via String(), database creation, and revalidation in a single roundtrip.

Example unsafe vs safe Server Action patterns

Unsafe example passes entire item object from client with no auth/ownership check: ```ts export async function completeItemUnsafe(item: Item) { await db.item.update({ where: { id: item.id }, data: { completed: true } }) } ``` Safe example takes only the ID, derives identity from session, verifies ownership: ```ts export async function completeItem(itemId: string) { const session = await auth() if (!session?.user) return const item = await db.item.findFirst({ where: { id: itemId, ownerId: session.user.id }, }) if (!item) return await db.item.update({ where: { id: item.id }, data: { completed: true } }) } ```

Example secure delete Server Action

```ts 'use server' import { auth } from '@/lib/auth' export async function deletePost(postId: string) { const session = await auth() if (!session?.user) throw new Error('Unauthorized') if (!(await canDelete(session.user, postId))) throw new Error('Forbidden') await db.post.delete({ where: { id: postId } }) } ``` This shows authentication and authorization checks before destructive operations.

Server Actions for SPA mutations

For data mutations in SPAs, Client Components call Server Actions to run mutations on the server. If already using SWR or TanStack Query, can write through an API route and revalidate with SWR's mutate or TanStack Query's invalidateQueries. A Server Action takes time and can fail. React provides useTransition, useOptimistic, useActionState, and useFormStatus to keep UI responsive while mutation runs, so mutation can feel as instant as client-rendered SPA.

Simple Server Action call with useTransition

In 'use client' component: import useTransition from React and deletePost from actions; in component, call const [isPending, startTransition] = useTransition(); in button, set disabled={isPending}, onClick={() => startTransition(() => deletePost(id))}, and show {isPending ? 'Deleting…' : 'Delete'} as button text.

Server Action reducer with useOptimistic and useActionState

For list-like state where each change appears instantly, combine useActionState with useOptimistic. Define a pure reducer that shows how each action changes the list, so client and server share one copy of logic. Server Action applies the reducer, persists result, returns next list. Client passes same reducer to useOptimistic for optimistic update, and server computes next state identically. A runAction helper applies optimistic change and dispatches Server Action in same transition, so every change shows immediately.

Server Actions provide secure authentication environment

Server Actions always execute on the server, providing a secure environment for handling authentication logic. They can be used with the form element and useActionState to capture user credentials, validate form fields, and call authentication provider APIs or databases.

Signup form with Server Action example

import { signup } from '@/app/actions/auth' export function SignupForm() { return ( <form action={signup}> <div> <label htmlFor="name">Name</label> <input id="name" name="name" placeholder="Name" /> </div> <div> <label htmlFor="email">Email</label> <input id="email" name="email" type="email" placeholder="Email" /> </div> <div> <label htmlFor="password">Password</label> <input id="password" name="password" type="password" /> </div> <button type="submit">Sign Up</button> </form> ) }

useActionState hook for form validation display

Use React's useActionState hook to display validation errors while the form is submitting. It returns [state, action, pending] where state contains errors for each field, action is passed to the form's action prop, and pending indicates if the form is submitting.

createSession function with cookie storage

import { cookies } from 'next/handlers' export async function createSession(userId: string) { const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) const session = await encrypt({ userId, expiresAt }) const cookieStore = await cookies() cookieStore.set('session', session, { httpOnly: true, secure: true, expires: expiresAt, sameSite: 'lax', path: '/', }) }

Server Action retry without try/catch when useOffline enabled

With experimental.useOffline enabled, a Server Action called with no network does not throw a fetch error. The call stays pending until the connection returns, the request runs again, and the awaited promise resolves with the server's response. No try/catch, no retry loop, or reconnection handler in the component is needed.

Combine useTransition with useOffline for offline-aware Server Action labels

Use useTransition to track pending state and useOffline to check connectivity. Combine both in the button label logic to display different messages like 'Pinging (offline, will retry)...' when offline versus 'Pinging...' when online but still pending.

Example Server Action retry with useOffline and useTransition

'use client' import { useState, useTransition } from 'react' import { useOffline } from 'next/offline' import { ping } from './actions' export function PingForm() { const [pongs, setPongs] = useState<string[]>([]) const [pending, startTransition] = useTransition() const isOffline = useOffline() function handleSubmit() { startTransition(async () => { const pong = await ping() setPongs((prev) => [pong, ...prev]) }) } const label = pending ? isOffline ? 'Pinging (offline, will retry)...' : 'Pinging...' : 'Ping' return ( <form action={handleSubmit}> <button type="submit" disabled={pending}> {label} </button> <ul> {pongs.map((t) => ( <li key={t}>{t}</li> ))} </ul> </form> ) } This demonstrates combining useTransition and useOffline to provide offline-aware feedback while a Server Action is pending.

POST requests prevent accidental CSRF side-effects

Next.js uses POST requests to handle mutations, which prevents accidental side-effects from GET requests and reduces Cross-Site Request Forgery (CSRF) risks.

Avoid mutations during rendering

Mutations such as logging out users, updating databases, or invalidating caches should never be side-effects in Server or Client Components. Next.js explicitly prevents setting cookies or triggering cache revalidation within render methods to avoid unintended side effects. Use Server Actions to handle mutations instead.

Secure action IDs in Server Actions

Next.js automatically creates encrypted, non-deterministic IDs for Server Actions to allow the client to reference and call them. These IDs are periodically recalculated between builds for enhanced security and are created during compilation and cached for a maximum of 14 days. They regenerate when a new build is initiated or the build cache is invalidated.

Dead code elimination for unused Server Actions

Unused Server Actions that are not referenced by their IDs are automatically removed from the client bundle during next build, preventing public access to unused endpoints.

Server Actions are directly callable via POST

By default, Server Actions are reachable via direct POST requests, not just through the application UI. Even if a Server Action is not imported elsewhere in code, it can still be called externally. Always verify authentication and authorization inside each Server Action and treat them as reachable via direct POST requests.

Re-verify authentication inside Server Actions

A page-level authentication check does not extend to Server Actions defined within it. Always re-verify authentication inside each Server Action independently. Page-level redirects control which UI is rendered, but Server Actions are separate entry points and must verify the caller themselves.

Rate limiting for expensive operations

For expensive operations like sending emails or writing to a database, consider adding rate limiting to prevent abuse. See the Rate limiting example in the Backend for Frontend guide.

Closure variables in Server Actions are automatically encrypted

When a Server Action is defined inside a component, it creates a closure with access to the outer function's scope. Closure variables are sent to the client and back to the server when the action is invoked. To prevent sensitive data from being exposed to the client, Next.js automatically encrypts closed-over variables. A new private key is generated for each action every time a Next.js application is built, meaning actions can only be invoked for a specific build.

Server Actions CSRF protection via Origin header validation

Server Actions use the POST HTTP method for invocation. Behind the scenes, Server Actions compare the Origin header to the Host header (or X-Forwarded-Host). If these don't match, the request is aborted. Server Actions can only be invoked on the same host as the page that hosts it, preventing most CSRF vulnerabilities when combined with SameSite cookies.

Give your agent this brain