Skip to main content

Transports

WIP

How a session travels between client and server, and how to choose between the cookie, bearer, JWT and composite transports

A transport decides how the session id reaches the client and comes back. It reads the credential off a request (extract), writes it onto a response (issue, as intents), and clears it (revoke). The engine holds one, createAuth({ transport }), and defaults to a cookie.

TransportCarriesRevocationUse it for
CookieThe sid in an HttpOnly cookie, plus a CSRF cookieImmediateBrowser apps on your own domain. The default.
BearerThe sid in Authorization: BearerImmediateNative and mobile apps, CLIs, scripts.
JWTA signed token the server verifies without a store readWhen the token expiresServices that must not hit the session store per request.
CompositeSeveral of the above at oncePer memberOne backend serving a browser and a native app.

DPoP is not a transport: it verifies proof-of-possession headers for a resource server that binds its tokens to a client key.

How a request resolves

auth.resolveSession({ headers }) asks the transport for the credential. When the transport can verify it on its own, as JWT does, that answer is used; otherwise the sid is hashed and looked up in the session store. A request without a credential reads as no session.

Writing your own

A transport is any object with extract, issue and revoke, and optionally verify for self-contained tokens:

import type { Transport } from '@gentleduck/auth/core/transport'

const headerTransport: Transport.ITransport = {
  extract: (req) => req.headers.get('x-session-id'),
  issue: (sid, session) => [{ type: 'json', status: 200, body: { sid, expiresAt: session.expiresAt } }],
  revoke: () => [{ type: 'json', status: 200, body: { revoked: true } }],
}

issue answers intents rather than touching a response, so the same transport works under every server adapter.