Skip to main content

Transports

WIP

How sessions ride on the request - Cookie, Bearer, JWT, Composite, and DPoP binding.

What is a transport?

A transport is the bridge between the in-memory Session and the wire. It owns three operations:

interface AuthTransport.ITransport {
  extract(req: { headers: Headers }): Promise<{ kind: 'session-id' | 'jwt'; value: string } | null>
  issue(session: Session, intents: Intent[]): Intent[]
  revoke(): Intent[]
}

You wire exactly one transport into AuthEngine.config.transport - or a CompositeTransport that tries several in order.

The four shipped transports

TransportWhat it doesWhen to pick it
CookieTransportSession id in an HttpOnly cookie.First-party web apps. Always the safest first choice.
BearerTransportOpaque token in Authorization: Bearer.Mobile / native / server-to-server.
JwtTransportStateless JWT + opaque refresh cookie.High-throughput APIs, microservices, OIDC issuer.
CompositeTransportTry several transports in order.Mixed web + API workloads on one origin.

Optionally bind any transport to a client public key with the DPoP verifier (RFC 9449) for sender-constrained tokens.

Quick comparison

CookieBearerJWT
Stateful (requires session store lookup)?yes yesyes yesno no
Survives XSS?yes HttpOnly(warning) depends on client storage(warning) depends on client storage
Survives CSRF?yes with __Host- + double-submityes no cookies, no CSRFyes no cookies
Browser refresh keeps you signed in?yes yesyes if client persistsyes if refresh cookie set
Token revocation?instant (delete row)instant (delete row)only at refresh (until JWT exp)
Issuing costone row writeone row writetwo row writes + JWT sign
Per-request costone row lookupone row lookupsignature verify only
Use casefirst-party webmobile / SPA cross-originmicroservices

Picking a transport

Decision tree:

Is this a first-party web app on a single origin?
  -> Cookie

Is this a mobile or native client?
  -> Bearer (store the token in the OS keychain)

Is this a microservice fleet that needs to verify tokens locally without a session store hit?
  -> JWT  (add DPoP for sender-constrained binding)

Is this an API that also serves a first-party web app on the same origin?
  -> Composite { primary: Cookie, fallback: [Bearer] }

Anatomy of an Intent

When a provider sign-in succeeds, the runtime emits Intent[]. The transport translates intents into wire commands:

type Intent =
  | { kind: 'startSession'; session: Session }   // mint a session, return the cookie / token
  | { kind: 'rotateSession'; session: Session }  // change the carrier - fixation defence
  | { kind: 'revokeSession'; sessionId: string }
  | { kind: 'redirect'; url: string; status?: 302 | 303 }  // OAuth provider hop
  | { kind: 'json'; status: number; body: unknown }
  | { kind: 'setCookie'; cookie: SetCookieDirective }
  | { kind: 'header'; name: string; value: string }

The framework adapter (server/express, server/hono, ...) walks the intents in order and converts them into native Response calls.

You almost never need to construct intents by hand - providers, flows, and the sessions facet do it for you.