Skip to content

@btravstack/http-server


@btravstack/http-server / oidc

oidc

Classes

OidcUnreachable

Defined in: packages/http-server/src/oidc.ts:39

Discovery did not answer, at boot. cause is whatever openid-client rejected with — a connection refused, a document that is not one, a 404 on .well-known — kept whole rather than flattened to a message, since the three read very differently to whoever is fixing the deployment.

Extends

  • TaggedErrorInstance<"OidcUnreachable", { cause: unknown; issuer: string; }>

Constructors

Constructor
ts
new OidcUnreachable(args): OidcUnreachable;

Defined in: node_modules/.pnpm/unthrown@5.8.0/node_modules/unthrown/dist/index.d.mts:2034

Parameters
ParameterType
argsobject & object
Returns

OidcUnreachable

Inherited from
ts
TaggedError("OidcUnreachable")<{
  readonly issuer: string;
  readonly cause: unknown;
}>.constructor

Properties

PropertyModifierTypeInherited fromDefined in
_tagreadonly"OidcUnreachable"TaggedError("OidcUnreachable")._tagnode_modules/.pnpm/unthrown@5.8.0/node_modules/unthrown/dist/index.d.mts:2011
causepublicunknownUnderScoped.causenode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.error.d.ts:24
issuerreadonlystringTaggedError("OidcUnreachable").issuerpackages/http-server/src/oidc.ts:40
messagepublicstringTaggedError("OidcUnreachable").messagenode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1075
namepublicstringTaggedError("OidcUnreachable").namenode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1074
stack?publicstringTaggedError("OidcUnreachable").stacknode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1076

Type Aliases

OidcOptions

ts
type OidcOptions<P> = object;

Defined in: packages/http-server/src/oidc.ts:57

Type Parameters

Type Parameter
P

Properties

PropertyModifierTypeDescriptionDefined in
allowInsecureIssuer?readonlybooleanTalk to an http: issuer that is NOT on a loopback host. Default false, and a ConfigInvalid at boot without it: the client secret, the code and every token cross the wire in cleartext, and allowInsecureRequests turns off the check that would have said so. An OPTION rather than a variable, on rule 6's own test: its silent change is a security regression, which is the argument securityHeaders is an option for. A loopback issuer — localhost, 127.0.0.1, [::1] — needs nothing, because plaintext that never leaves the machine is the dev loop's own Ory.packages/http-server/src/oidc.ts:98
clientId?readonlystringPins HTTP_OIDC_CLIENT_ID.packages/http-server/src/oidc.ts:61
clientSecret?readonlystringPins HTTP_OIDC_CLIENT_SECRET — this is a confidential client.packages/http-server/src/oidc.ts:63
issuer?readonlystringPins HTTP_OIDC_ISSUER — the provider, as its discovery document names itself.packages/http-server/src/oidc.ts:59
postLogout?readonly`/${string}`Where a logout lands when the provider advertises no end_session_endpoint. Default /.packages/http-server/src/oidc.ts:85
prefix?readonly`/${string}`Where the three routes are mounted. Default /auth.packages/http-server/src/oidc.ts:71
principalreadonly(claims) => P | undefinedWhat the ID token's claims make the caller — the same shape jwtAuthenticator takes, so one function serves both. Answering undefined refuses the login: the claim this application requires and the standard does not, such as a tenant.packages/http-server/src/oidc.ts:80
redirectUri?readonlystringPins HTTP_OIDC_REDIRECT_URI — the URI REGISTERED with the provider, which is also what the code grant is checked against. It is never rebuilt from the request's Host.packages/http-server/src/oidc.ts:69
scope?readonlystringWhat the authorization request asks for. Default openid.packages/http-server/src/oidc.ts:73

Functions

oidc()

ts
function oidc<P>(options): Provider<HttpHandler, OidcUnreachable | ConfigInvalid, Env | SessionCodec | Observers> & object;

Defined in: packages/http-server/src/oidc.ts:443

The login answerer: three routes that log a browser in over the authorization-code flow with PKCE and hand the result to SessionCodec as a session cookie.

ts
export const BrowserApi = HttpModule("BrowserApi")({
  fragments,
  fragmentsLogin: "/auth/login",
  provides: [sessionCodec(), oidc({ principal: identityOf })],
});
  • GET <prefix>/login?return=<path>&as=<hint> seals a PKCE verifier, state, nonce and where to return to into the five-minute __Host-oidc cookie and redirects to the provider. return is the seam htmx({ login }) writes; as rides through as login_hint.
  • GET <prefix>/callback checks state against that cookie, exchanges the code, and seals principal(claims) into __Host-session — clearing the transient in the same answer.
  • POST <prefix>/logout clears the session and sends the browser to the provider's end_session_endpoint, or to postLogout when it advertises none.

Each of the three routes is an OPERATION reported to Observers, the way a cache read is: a refusal settles error carrying its own reason, so a rotated client secret is one dimension rather than an indistinguishable spike of bad logins. It costs a root nothing — httpServer already contributes the no-op member — and a root composing observability() gets the line for free.

It injects SessionCodec rather than holding keys, so the codec that seals a session here is the one sessionAuthenticator reads it back with — and a root composing this without sessionCodec() is di's own unmet need naming the port.

Type Parameters

Type Parameter
P

Parameters

ParameterType
optionsOidcOptions<P>

Returns

Provider<HttpHandler, OidcUnreachable | ConfigInvalid, Env | SessionCodec | Observers> & object

Released under the MIT License.