---
title: "Sessions"
url: "https://effect-auth.itsbroly.com/concepts/sessions/"
description: "Understand session validation, rotation, and revocation."
---



A session is effect-auth's durable proof that a particular authentication ceremony completed for a user. It is intentionally a **technical session**, not a user profile: the current-session response identifies the user and records authentication assurance, but it does not load names, preferences, roles, or an application user object. Use `userId` to authorize the request and, when needed, expose a separate application-owned user/profile endpoint.

## Cookie and server row [#cookie-and-server-row]

The browser receives an opaque token shaped as `sessionId.secret`. `SessionCookie` reads and serializes that token; by default it uses `__Host-session`, `Secure`, `HttpOnly`, `SameSite=Lax`, and `Path=/`. JavaScript should not read or persist it. The browser sends it with requests while the server keeps the authoritative session row.

| Value                                               | Where it lives                         | Purpose                                                       |
| --------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------- |
| `sessionId`                                         | Cookie and row                         | Selects the session record                                    |
| Secret / `secretHash`                               | Raw secret only in cookie; hash in row | Proves possession without storing the bearer secret           |
| `userId`                                            | Row and responses                      | Connects the session to the application identity              |
| Authentication events                               | Row only                               | Server-side provenance used to derive assurance and freshness |
| `authTime`, `aal`, `amr`, `mfaVerifiedAt`           | Row and responses                      | Derived summaries for guards and browser UI                   |
| `createdAt`, `lastSeenAt`, `expiresAt`, `revokedAt` | Row                                    | Controls activity, expiry, listing, and revocation            |

The stored secret is an HMAC-SHA-256 digest made with the configured session key. Validation hashes the presented secret and compares it safely with `secretHash`; a database read alone therefore does not reveal a usable cookie. Protect both the session key and the cookie, because either is security-sensitive.

## Lifecycle [#lifecycle]

```text
authentication succeeds
        |
        v
 create row + issue token --> commit Set-Cookie --> validate each request
        ^                                             |
        |                                             v
        +----- rotate secret <----- refresh idle expiry when due
                       |                         |
                       +---- old token fails     |
                                                 v
                         revoke / expire --> unauthenticated
                                   |
                              clear cookie
```

An authentication flow creates the row and returns an `IssuedSession`. At the standard HTTP boundary, `AuthHttp` commits it through `SessionCookie`; application code should not manually return the token. Password, MFA, and other built-in flows own this create-and-commit transition.

Every authenticated operation reads the cookie and validates the row. Validation rejects malformed tokens, missing rows, secret mismatches, revoked sessions, and sessions past either expiry limit. The default policy has a 30-day idle TTL, a 90-day absolute TTL, and a one-day refresh threshold. Effective expiry is the earlier of idle expiry and `authTime + absoluteTtl`.

Refresh validates the same token and, when due, advances `lastSeenAt` and idle expiry without crossing the absolute limit. It does **not** change the secret. Rotation generates a new secret for the existing session ID and row. Assurance transitions use a compare-and-set mutation that appends verified evidence and rotates atomically: exactly one concurrent transition wins, the old token is invalid immediately, and the caller receives one replacement token. The standard factor-specific HTTP operations commit that replacement cookie. A custom transport must commit it itself and handle a response lost after storage commits.

Revocation marks server state, so it takes effect on the next validation even if a browser still holds its cookie. Logout attempts to revoke the current valid row and clears the cookie; an absent or already-invalid cookie is still cleared. The standard revoke endpoint verifies that the target session belongs to the authenticated user. Revoking the current session also clears its cookie, while `revokeOthers` preserves the current row. Listing returns only active sessions for that user. Storage failures are server errors; expected invalid, expired, or revoked credentials become an unauthenticated response rather than exposing why validation failed.

## Authentication context [#authentication-context]

Authentication events are the source of truth. Core derives `aal`, canonical `amr`, `authTime`, and `mfaVerifiedAt`; callers do not select them. Method freshness and stable-factor freshness use the matching event's `verifiedAt`, not one shared session timestamp. Raw events include credential/factor provenance and remain server-only. Normal HTTP schemas and client session types expose only derived summaries.

The local tiers are `aal1` for a verified basic authenticator/channel, `aal2` for a verified strong authenticator or independent second factor under the central policy, and `aal3` for explicitly registered custom hardware-bound policy; no built-in flow establishes `aal3`. These project-local names are inspired by AAL terminology. &#x2A;*Effect Auth does not automatically provide or claim NIST SP 800-63 conformance.** Conformance depends on the complete authenticator, identity proofing, lifecycle, deployment, and operational controls.

Canonical built-in AMR values are `pwd`, `email_otp`, `magic_link`, `oauth`, `totp`, `passkey`, and `recovery_code`. A passkey reaches local `aal2` only when user verification was verified by the server. Recovery-code evidence creates constrained remediation state and is not ordinary `aal2`.

The browser client exposes the standard session operations without exposing the cookie:

```ts
import { createAuthClient } from "@effect-auth/core/Client";

const auth = createAuthClient();
const session = await auth.session.currentOrUndefined();

if (session?.aal !== "aal2") {
  // Start the application's step-up flow before the sensitive operation.
}
```

`currentOrUndefined` converts only the typed unauthenticated result to `undefined`; network, decoding, and internal failures still reject. `auth.session.refresh()` explicitly refreshes and recommits expiry, while `list`, `revoke`, `revokeOthers`, and `logout` support account session management. See [Browser Client](/clients/browser-client/) for transport and cross-origin cookie requirements.

## Ownership [#ownership]

Prefer the standard HttpApi session operations when their behavior fits: they own cookie reading, public error mapping, origin protection for mutating operations, user-scoped revocation, and response commitment. Calling the public `Sessions` or `SessionCookie` services directly is appropriate for a custom protocol, but then the application owns those omitted transport and security decisions, including committing every newly issued or rotated token and clearing cookies after revocation.

Continue with [Password](/authentication/password/), [MFA](/authentication/mfa/), [Step-up](/authentication/step-up/), and [Security Policies](/concepts/security-policies/).

