@btravstack/http-server / session
session
Classes
CookieSchemes
Defined in: packages/http-server/src/session.ts:89
One member per composed scheme, true when that scheme reads a cookie — the graph fact csrf's default is computed from. httpServer contributes the false member that keeps the set from being the empty dependency di refuses, so a graph composing no scheme at all still starts.
A set port rather than a marker HttpModule folds: http() never sees an application's authenticators — the root composes them itself — so a signal read off the options record would leave that surface silently unprotected. A ctx.get at start could not answer it either: di's Context has no has.
Extends
PortInstance<"HttpCookieSchemes", readonlyboolean[]> &object
Constructors
Constructor
new CookieSchemes(): CookieSchemes;Defined in: packages/di/dist/index.d.mts:30
Returns
Inherited from
Port.many("HttpCookieSchemes")<boolean>.constructorProperties
SessionCodec
Defined in: packages/http-server/src/session.ts:76
Extends
PortInstance<"HttpSessionCodec",SessionCodecService>
Constructors
Constructor
new SessionCodec(): SessionCodec;Defined in: packages/di/dist/index.d.mts:16
Returns
Inherited from
Port("HttpSessionCodec")<SessionCodecService>.constructorProperties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
[ID] | readonly | "HttpSessionCodec" | Port("HttpSessionCodec").[ID] | packages/di/dist/index.d.mts:12 |
[SERVICE] | readonly | SessionCodecService | Port("HttpSessionCodec").[SERVICE] | packages/di/dist/index.d.mts:13 |
portId | readonly | "HttpSessionCodec" | Port("HttpSessionCodec").portId | packages/di/dist/index.d.mts:17 |
Type Aliases
Session
type Session<P> = object;Defined in: packages/http-server/src/session.ts:18
What the cookie carries: the application's own principal, and when the session ends.
The sealed payload also holds a typ marker this type does not declare — seal writes it and unseal requires it, so nothing outside this module sets or reads one. A session put back on the wire whole would carry it; send the principal, not the session.
Type Parameters
| Type Parameter |
|---|
P |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
exp | readonly | number | - | packages/http-server/src/session.ts:32 |
iat | readonly | number | - | packages/http-server/src/session.ts:31 |
principal | readonly | P | - | packages/http-server/src/session.ts:19 |
scopes? | readonly | readonly string[] | What the login recorded the session as holding. A scheme grants the INTERSECTION of its own vocabulary with this, so a session naming a scope the scheme does not know grants nothing extra. | packages/http-server/src/session.ts:30 |
sid? | readonly | string | The provider's session id, kept for logout; absent when the session was not minted by an OIDC login. | packages/http-server/src/session.ts:24 |
SessionCodecService
type SessionCodecService = object;Defined in: packages/http-server/src/session.ts:35
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
seal | readonly | (session) => AsyncResult<string, never> | Seals a session into a JWE. iat and exp are stamped here rather than accepted, so a caller cannot mint a session that outlives the policy. | packages/http-server/src/session.ts:49 |
transient | readonly | object | The login flow's own state — a PKCE verifier, state, nonce, where to return to — sealed with the SAME keys under its own purpose marker and a five-minute lifetime. A transient read as a session, or a session read as one, is undefined: the marker is what separates them. typ, iat and exp are the CODEC's: seal writes them over whatever the state carries and unseal strips them off again, so a caller's own value under one of those three names never survives the round trip — which is what stops state built from a request deciding what the payload is. | packages/http-server/src/session.ts:68 |
transient.seal | readonly | (state) => AsyncResult<string, never> | - | packages/http-server/src/session.ts:69 |
transient.unseal | readonly | (cookie) => AsyncResult<Readonly<Record<string, string>> | undefined, never> | - | packages/http-server/src/session.ts:70 |
ttlSec | readonly | number | What seal stamps, in seconds — the whole session, since there is no sliding re-seal. It is published because a login has to write the same number into the cookie's Max-Age: a browser holding the cookie longer than the payload lives is a caller who looks anonymous with a cookie still attached, and one holding it for less is a session cut short by the wrapper rather than by the policy. | packages/http-server/src/session.ts:44 |
unseal | readonly | (cookie) => AsyncResult<Session<unknown> | undefined, never> | The cookie's value, opened with whichever key still holds it. Every failure — no cookie, not a JWE, a key that is gone, a tampered ciphertext, a session past its exp — is the same undefined: an anonymous caller, never an error and never a hint about which of those it was. | packages/http-server/src/session.ts:56 |
SessionOptions
type SessionOptions<P, Scopes> = object;Defined in: packages/http-server/src/session.ts:314
Type Parameters
| Type Parameter |
|---|
P |
Scopes extends readonly string[] |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
principal? | readonly | (session) => P | undefined | What the session makes the caller. Answering undefined refuses it — the hook for a session this endpoint will not take, and the default's own answer to a session sealed with no principal at all. | packages/http-server/src/session.ts:327 |
scopes? | readonly | Scopes | The scopes this scheme can grant, and the only place they are written — jwtAuthenticator's rule, for jwtAuthenticator's reason. The grant is the INTERSECTION of this vocabulary with what the session carries. Omit it entirely for a scheme with no scopes. | packages/http-server/src/session.ts:321 |
Variables
DEFAULT_TTL_SEC
const DEFAULT_TTL_SEC: 43200 = 43_200;Defined in: packages/http-server/src/session.ts:100
Twelve hours, fixed: there is no sliding re-seal, so this is the whole session.
SESSION_COOKIE
const SESSION_COOKIE: "__Host-session" = "__Host-session";Defined in: packages/http-server/src/session.ts:312
The cookie the session travels on, and there is no option to rename it.
__Host- is a prefix the BROWSER enforces — Secure, Path=/, no Domain — which is the guarantee, and it is the name oidc() writes as well: the scheme that READS the cookie and the answerer that SEALS it must agree, and two options that must agree is the shape where they silently do not. One constant both name.
TRANSIENT_TTL_SEC
const TRANSIENT_TTL_SEC: 300 = 300;Defined in: packages/http-server/src/session.ts:103
Five minutes, and not an option: a login that takes longer is a login to start again.
Functions
cookieScheme()
function cookieScheme(): AnyProvider;Defined in: packages/http-server/src/session.ts:92
What defineHttp contributes for a scheme whose description says it reads a cookie.
Returns
AnyProvider
csrfOn()
function csrfOn(option, schemes): boolean;Defined in: packages/http-server/src/session.ts:96
csrf unset is on exactly when a composed scheme reads a cookie.
Parameters
| Parameter | Type |
|---|---|
option | boolean | undefined |
schemes | readonly boolean[] |
Returns
boolean
sessionAuthenticator()
function sessionAuthenticator<P>(): <Scopes>(options) => Authenticator<P, Scopes[number], SessionCodec, never>;Defined in: packages/http-server/src/session.ts:352
The session-cookie scheme: a third one beside jwtAuthenticator and apiKeyAuthenticator, so requires: [{ session: [] }] on a fragment route and authenticated({ session: [...] }) on a procedure need nothing new.
export const browserAuth = sessionAuthenticator<Identity>()({ scopes: ["orders:export"] });The cookie is SESSION_COOKIE and cannot be renamed: oidc() seals that name, so a knob here would be one half of a pair that must agree.
It injects SessionCodec rather than holding keys of its own, so a root composing this scheme without sessionCodec() is di's own unmet need naming SessionCodec — and the codec that reads a cookie is the very one that sealed it.
No cookie, a cookie no key opens, a session past its exp and a principal the application declined are ONE answer: Unauthenticated, carrying no reason, which is the codec's own rule one layer up.
Type Parameters
| Type Parameter |
|---|
P |
Returns
<Scopes>(options) => Authenticator<P, Scopes[number], SessionCodec, never>
sessionCodec()
function sessionCodec(pins?): Provider<SessionCodec, ConfigInvalid, Env> & object;Defined in: packages/http-server/src/session.ts:267
The cookie codec, from HTTP_SESSION_KEYS — a comma-separated list of base64url 32-byte keys. The first seals, every one unseals, so rotation is prepend, deploy, drop; a cookie sealed with a dropped key is anonymous rather than an error.
A key that is not 32 bytes is a ConfigInvalid naming the variable, at boot, rather than a failure at the first request.
Parameters
| Parameter | Type |
|---|---|
pins | { keys?: readonly string[]; ttlSec?: number; } |
pins.keys? | readonly string[] |
pins.ttlSec? | number |
Returns
Provider<SessionCodec, ConfigInvalid, Env> & object