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

React Router · Guides · all subjects

sessions-and-cookies

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

createCookieSessionStorage configuration

createCookieSessionStorage takes a configuration object with a cookie property. The cookie can be a Cookie from createCookie or a CookieOptions object with these optional fields: name (string), domain (string), httpOnly (boolean), maxAge (number in seconds), path (string), sameSite (string), secure (boolean), secrets (array of strings for signing), and expires (Date). Expires can be set but is not recommended as it creates a static date on server deployment. maxAge overrides expires when both are used.

Session storage functions setup location

It is recommended to set up the session storage object in app/sessions.server.ts so all routes that need to access session data can import from the same location.

getSession and commitSession input/output

getSession() retrieves the current session from the incoming request's Cookie header. commitSession() and destroySession() provide the Set-Cookie header for the outgoing response.

Session object methods

After retrieving a session with getSession(), the returned session object has methods including session.get(key) to retrieve a value and session.has(key) to check if a key exists. Additional methods are documented in the Session API.

Logout must be performed in action, not loader

It is important to perform logout or any mutation in an action function, not a loader. Otherwise you open users to Cross-Site Request Forgery (CSRF) attacks.

Session flash and nested routes race conditions

Because of nested routes, multiple loaders can be called to construct a single page. When using session.flash() or session.unset(), ensure no other loaders in the request will try to read that data, otherwise you get race conditions. If using flash, typically have a single loader read it. If another loader needs a flash message, use a different key for that loader.

createSessionStorage CRUD operations

createSessionStorage() requires a cookie (for session ID persistence) and CRUD methods: createData(data, expires) called from commitSession on initial session creation when no session ID exists; readData(id) called from getSession when a session ID exists in the cookie; updateData(id, data, expires) called from commitSession when a session ID already exists; deleteData(id) called from destroySession. The expires argument is a Date after which the data should be considered invalid.

Cookie creation for React Router

In React Router, cookies are typically created using createCookie(name, options) and are accessed in loader and action functions. The loader reads the cookie header and parses it; the action modifies the cookie and returns it in a Set-Cookie header.

Cookie attributes configuration

Cookie attributes can be specified either in createCookie(name, options) as defaults, or during serialize() when the Set-Cookie header is generated. Available attributes are: path (string), sameSite (string), httpOnly (boolean), secure (boolean), expires (Date), and maxAge (number in seconds). These attributes control when cookies expire, how they are accessed, and where they are sent.

Cookie signing with secrets

Provide one or more secrets when creating a cookie using createCookie(name, {secrets: ["s3cret1"]}) to sign the cookie and automatically verify its contents when received. Cookies with secrets are stored and verified to ensure integrity. Secrets can be rotated by adding new secrets to the front of the secrets array. Old secrets still decode successfully in cookie.parse(), while the newest secret (first in the array) is used for outgoing cookies in cookie.serialize().

Login form example with session

In a login route, the loader checks if the user has a userId in the session and redirects to home if already signed in. The loader retrieves any error flash message and returns it in Set-Cookie header via commitSession. The action retrieves form data (username and password), validates credentials, and either sets session.flash("error", message) and redirects to login, or sets session.set("userId", userId) and redirects to home. Both cases use Set-Cookie header with commitSession.

Logout route example

A logout route has an action that retrieves the session from the Cookie header, then returns a redirect to login with a Set-Cookie header containing destroySession(session). The component displays a confirmation message with a Form that has method="post" to trigger the action.

User preferences cookie example

A user preferences cookie can be created with createCookie("user-prefs", {maxAge: 604_800}) for a one-week expiration. In the loader, parse the cookie header with userPrefs.parse(cookieHeader) and return the parsed value. In the action, parse the cookie, modify it based on form data, and return a redirect with Set-Cookie header containing userPrefs.serialize(cookie). The component uses the loader data to conditionally render based on cookie values.

Additional session storage utilities

React Router provides several session storage utilities: isSession, createMemorySessionStorage (for local dev and testing), createSession (for custom storage), createFileSessionStorage (for Node), createWorkersKVSessionStorage (for Cloudflare Workers), and createArcTableSessionStorage (for Architect and Amazon DynamoDB).

Additional cookie utilities

React Router provides additional cookie utilities: isCookie and createCookie.

createCookieSessionStorage example code

Example of creating cookie session storage: import { createCookieSessionStorage } from "react-router"; type SessionData = { userId: string; }; type SessionFlashData = { error: string; }; const { getSession, commitSession, destroySession } = createCookieSessionStorage<SessionData, SessionFlashData>( { cookie: { name: "__session", domain: "reactrouter.com", httpOnly: true, maxAge: 60, path: "/", sameSite: "lax", secrets: ["s3cret1"], secure: true, }, }, ); export { getSession, commitSession, destroySession };

createSessionStorage example code

Example of creating custom session storage with database: import { createSessionStorage } from "react-router"; function createDatabaseSessionStorage({ cookie, host, port, }) { const db = createDatabaseClient(host, port); return createSessionStorage({ cookie, async createData(data, expires) { const id = await db.insert(data); return id; }, async readData(id) { return (await db.select(id)) || null; }, async updateData(id, data, expires) { await db.update(id, data); }, async deleteData(id) { await db.delete(id); }, }); } const { getSession, commitSession, destroySession } = createDatabaseSessionStorage({ host: "localhost", port: 1234, cookie: { name: "__session", sameSite: "lax", }, });

Cookie creation example code

Example of creating a cookie for user preferences: import { createCookie } from "react-router"; export const userPrefs = createCookie("user-prefs", { maxAge: 604_800, // one week });

Cookie attributes with defaults example code

Example of cookie with attributes and defaults: const cookie = createCookie("user-prefs", { path: "/", sameSite: "lax", httpOnly: true, secure: true, expires: new Date(Date.now() + 60_000), maxAge: 60, }); // Use defaults cookie.serialize(userPrefs); // Override individual ones cookie.serialize(userPrefs, { sameSite: "strict" });

Cookie secret rotation example code

Example of rotating cookie secrets: export const cookie = createCookie("user-prefs", { secrets: ["n3wsecr3t", "olds3cret"], }); Then in a route: import { data } from "react-router"; import { cookie } from "../cookies.server"; import type { Route } from "./+types/my-route"; export async function loader({ request, }: Route.LoaderArgs) { const oldCookie = request.headers.get("Cookie"); // oldCookie may have been signed with "olds3cret", but still parses ok const value = await cookie.parse(oldCookie); return data("...", { headers: { // Set-Cookie is signed with "n3wsecr3t" "Set-Cookie": await cookie.serialize(value), }, }); }

Sessions are per-route based in React Router

In React Router, sessions are managed on a per-route basis (rather than via middleware like in Express) in loader and action methods using a SessionStorage object that implements the SessionStorage interface. Session storage understands how to parse and generate cookies and how to store session data in a database or filesystem.

Give your agent this brain