Security

What's actually in your session cookie

Rails signs the session cookie, so users can read it but not forge it. That distinction decides what may go in it.

18 July 2026 2 min read Mohammad Aaquib Jawed

Rails stores the session in a cookie by default. The cookie is signed and encrypted with your secret key base, which means it cannot be forged — and it is still sitting on the user's machine.

Signed means tamper-proof, not private

With modern defaults the session is encrypted as well as signed, so contents are not readable. But the design intent is still that a session is a small set of identifiers, not a data store.

Two practical limits. Cookies are capped at around 4KB, and exceeding it fails in confusing ways. And every request carries the whole cookie, so a large session is bandwidth on every single request including asset requests in some configurations.

The reasonable contents are a user id, a handful of flags, and a CSRF token. Anything else belongs server-side.

The flags that matter

httponly stops JavaScript reading the cookie, which limits what an XSS bug can steal. secure stops it being sent over plain HTTP. same_site controls whether it rides along on cross-site requests, and is the main structural defence against CSRF.

Rails sets sensible defaults for all three. The failure mode is a hand-rolled cookie elsewhere in the application that does not, and those are worth grepping for.

Fixation and rotation

If the session identifier does not change when privileges change, an attacker who established a session before login may still hold a valid one after.

Resetting the session on login, and again on logout, closes it. This is one line and it is frequently missing in hand-rolled authentication.

Rotate the session at every privilege boundary. Logging in is the obvious one; logging out is the one people skip.

Logout has to mean something

With cookie sessions there is no server-side record to delete, so "logging out" is really "asking the browser to forget". A copied cookie remains valid until it expires.

If you need genuine revocation — logging out other devices, terminating a session after a password change — you need server-side state: a session store, or a token in the cookie you can check against a database and invalidate. Choose deliberately, because the default cannot revoke.

Secret rotation

Everything above depends on the secret key base. If it leaks, sessions can be forged.

Rotating it invalidates every existing session, which logs everyone out — annoying but correct after a leak. Knowing this in advance turns an incident decision into a procedure, and it is worth writing down before you need it.

All writing Reply by email