@btravstack/http-server / session
session
Classes
CookieSchemes
Defined in: packages/http-server/src/cookie.ts:51
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: the starter never sees an application's authenticators — the module sugar provides them — so a signal read off the options record would leave a scheme it did not see unprotected. A ctx.get at start could not answer it either: di's Context has no has.
A member is owed by anything that READS OR WRITES a cookie, which is wider than "an authenticator": oidc() is not a scheme and contributes one.
Extends
PortInstance<"HttpCookieSchemes", readonlyboolean[]> &object
Constructors
Constructor
new CookieSchemes(): CookieSchemes;Defined in: packages/di/dist/index.d.mts:29
Returns
Inherited from
Port.many("HttpCookieSchemes")<boolean>.constructor
Properties
SessionCodec
Defined in: packages/http-server/src/session.ts:99
Extends
PortInstance<"HttpSessionCodec",SessionCodecService>
Constructors
Constructor
new SessionCodec(): SessionCodec;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpSessionCodec")<SessionCodecService>.constructor
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
[ID] | readonly | "HttpSessionCodec" | Port("HttpSessionCodec").[ID] | packages/di/dist/index.d.mts:11 |
[SERVICE] | readonly | SessionCodecService | Port("HttpSessionCodec").[SERVICE] | packages/di/dist/index.d.mts:12 |
portId | static readonly | "HttpSessionCodec" | Port("HttpSessionCodec").portId | packages/di/dist/index.d.mts:16 |
Type Aliases
Session
type Session<P> = object;Defined in: packages/http-server/src/session.ts:30
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 |
|---|---|---|---|---|
clientId? | readonly | string | The client id of the login that minted the session — two logins may share an issuer. | packages/http-server/src/session.ts:53 |
exp | readonly | number | - | packages/http-server/src/session.ts:55 |
iat | readonly | number | - | packages/http-server/src/session.ts:54 |
iss? | readonly | string | The issuer of the login that minted the session, as that login is configured. With Session.clientId it names the login: sessionAuthenticator refuses a session from any other, so a second login's session is never read as the first's. | packages/http-server/src/session.ts:51 |
principal | readonly | P | - | packages/http-server/src/session.ts:31 |
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:44 |
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:38 |
tokenRef? | readonly | string | Opaque server-side credential reference, never an access or refresh token. | packages/http-server/src/session.ts:33 |
SessionCodecPins
type SessionCodecPins = object;Defined in: packages/http-server/src/session.ts:272
What sessionCodec is handed.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
keys? | readonly | readonly string[] | packages/http-server/src/session.ts:273 |
ttlSec? | readonly | number | packages/http-server/src/session.ts:274 |
SessionCodecService
type SessionCodecService = object;Defined in: packages/http-server/src/session.ts:58
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:72 |
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:91 |
transient.seal | readonly | (state) => AsyncResult<string, never> | - | packages/http-server/src/session.ts:92 |
transient.unseal | readonly | (cookie) => AsyncResult<Readonly<Record<string, string>> | undefined, never> | - | packages/http-server/src/session.ts:93 |
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:67 |
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:79 |
SessionOptions
type SessionOptions<P, Scopes, Pre> = object;Defined in: packages/http-server/src/session.ts:346
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Scopes extends readonly string[] | - |
Pre extends string | string |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
clientId? | readonly | string | That login's client id — pins <prefix>_CLIENT_ID. A session from another issuer, another client, or none is refused. | packages/http-server/src/session.ts:371 |
issuer? | readonly | string | The issuer of the login whose sessions this scheme accepts — pins <prefix>_ISSUER, the variable that login reads too. | packages/http-server/src/session.ts:366 |
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:361 |
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:353 |
tokens? | readonly | PortClassOf<string, OidcTokensService> | Validate server-side session revocation with this login’s token manager. | packages/http-server/src/session.ts:355 |
variablePrefix? | readonly | Pre | The prefix of both variables. Default HTTP_OIDC, oidc()'s own — a scheme pairs with its login by naming the same prefix. | packages/http-server/src/session.ts:376 |
Variables
DEFAULT_TTL_SEC
const DEFAULT_TTL_SEC: 43200 = 43_200;Defined in: packages/http-server/src/session.ts:102
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:344
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:105
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/cookie.ts:63
What every cookie surface contributes — defineHttp for a scheme whose description says it reads one, and oidc() for itself, which is not a scheme at all but reads __Host-oidc and serves a state-changing POST /logout.
"Whatever touches a cookie contributes" is the rule, not "whatever authenticates": the narrower reading left a root composing oidc() and sessionCodec() without sessionAuthenticator serving that logout with CSRF off.
Returns
AnyProvider
sessionAuthenticator()
function sessionAuthenticator<P>(): <O>(options) => Authenticator<P, ScopesOf<O>[number],
| SessionCodec
| EnvReading<
| Unpinned<O, "issuer", `${PrefixOf<O, "HTTP_OIDC">}_ISSUER`>
| Unpinned<O, "clientId", `${PrefixOf<O, "HTTP_OIDC">}_CLIENT_ID`>,
| MaybePinned<O, "issuer", `${PrefixOf<O, "HTTP_OIDC">}_ISSUER`>
| MaybePinned<O, "clientId", `${PrefixOf<O, "HTTP_OIDC">}_CLIENT_ID`>>
| O extends object ? InstanceType<Extract<T, AnyPort>> : never, ConfigInvalid>;Defined in: packages/http-server/src/session.ts:408
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.
It accepts only sessions its own login minted: the issuer and client id are sealed in the session and must equal this scheme's, bound like oidc()'s from HTTP_OIDC_ISSUER and HTTP_OIDC_CLIENT_ID, or under the same variablePrefix. Two logins share one cookie and one key list, so the name of a cookie could not keep them apart.
No cookie, a cookie no key opens, a session past its exp, a session from another issuer 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
<O>(options) => Authenticator<P, ScopesOf<O>[number], | SessionCodec | EnvReading< | Unpinned<O, "issuer", `${PrefixOf<O, "HTTP_OIDC">}_ISSUER`> | Unpinned<O, "clientId", `${PrefixOf<O, "HTTP_OIDC">}_CLIENT_ID`>, | MaybePinned<O, "issuer", `${PrefixOf<O, "HTTP_OIDC">}_ISSUER`> | MaybePinned<O, "clientId", `${PrefixOf<O, "HTTP_OIDC">}_CLIENT_ID`>> | O extends object ? InstanceType<Extract<T, AnyPort>> : never, ConfigInvalid>
sessionCodec()
function sessionCodec<O>(pins?): Provider<SessionCodec, ConfigInvalid, EnvReading<Unpinned<O, "keys", "HTTP_SESSION_KEYS">, MaybePinned<O, "keys", "HTTP_SESSION_KEYS">>> & object;Defined in: packages/http-server/src/session.ts:288
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 append, promote, drop — one rollout each, so a key is unsealable on every replica before any replica seals with it; 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.
Type Parameters
| Type Parameter | Default type |
|---|---|
O extends SessionCodecPins | Record<never, never> |
Parameters
| Parameter | Type |
|---|---|
pins? | O & OptionsAs<O, SessionCodecPins> |
Returns
Provider<SessionCodec, ConfigInvalid, EnvReading<Unpinned<O, "keys", "HTTP_SESSION_KEYS">, MaybePinned<O, "keys", "HTTP_SESSION_KEYS">>> & object