remix-run/remix · critical · Error

Session cookie must be signed

Error message

Session cookie must be signed

What it means

The session() middleware requires the session cookie to be signed, because unsigned cookies can be forged by clients. It throws immediately at middleware construction time if cookie.signed is not enabled.

Source

Thrown at packages/session-middleware/src/lib/session.ts:17

import type { Cookie } from '@remix-run/cookie'
import type { Middleware } from '@remix-run/fetch-router'
import { Session, type SessionStorage } from '@remix-run/session'

/**
 * Middleware that manages request session state on request context.
 *
 * @param sessionCookie The session cookie to use
 * @param sessionStorage The storage backend for session data
 * @returns The session middleware
 */
export function session(
  sessionCookie: Cookie,
  sessionStorage: SessionStorage,
): Middleware<{ key: typeof Session; value: Session; property: 'session' }> {
  if (!sessionCookie.signed) {
    throw new Error('Session cookie must be signed')
  }

  if (sessionCookie.httpOnly === false) {
    console.warn(
      `Session cookie "${sessionCookie.name}" is configured with httpOnly: false and may be accessible to client-side JavaScript.`,
    )
  }

  return async (context, next) => {
    if (context.has(Session)) {
      throw new Error('Existing session found, refusing to overwrite')
    }

    let cookieValue = await sessionCookie.parse(context.headers.get('Cookie'))
    let session = await sessionStorage.read(cookieValue)

    context.set(Session, session, { property: 'session' })

View on GitHub (pinned to 9696913134)

Solutions

  1. Create the cookie with one or more secrets: cookie('session', { secrets: ['...'] })
  2. Ensure the secrets array is non-empty
  3. Load the secret from an environment variable rather than hardcoding

Example fix

// before
let cookie = createCookie('session', { path: '/' })
session(cookie, storage)
// after
let cookie = createCookie('session', { secrets: [process.env.SESSION_SECRET] })
session(cookie, storage)
Defensive patterns

Strategy: validation

Validate before calling

if (!sessionCookie.signed) throw new Error('Configure cookie secrets before using session middleware')

Prevention

When it happens

Trigger: Calling session(cookie, storage) where the Cookie was created without a secret (or with signed: false), e.g. cookie('session', { path: '/' }) with no secrets option.

Common situations: Copying a plain cookie definition into session middleware setup; forgetting the secrets option when migrating from another session library; assuming signing is configured elsewhere.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/ef462b677abd85d3. Report an issue: GitHub.