@btravstack/http-server / oidc
oidc
Classes
OidcUnreachable
Defined in: packages/http-server/src/oidc-discovery.ts:16
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
new OidcUnreachable(args): OidcUnreachable;Defined in: node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2386
Parameters
| Parameter | Type |
|---|---|
args | object & object |
Returns
Inherited from
TaggedError("OidcUnreachable")<{ readonly issuer: string; readonly cause: unknown; }>.constructor
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
_tag | readonly | "OidcUnreachable" | TaggedError("OidcUnreachable")._tag | node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2363 |
cause | public | unknown | AuthenticatorUnavailable.cause | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.error.d.ts:24 |
issuer | readonly | string | TaggedError("OidcUnreachable").issuer | packages/http-server/src/oidc-discovery.ts:17 |
message | public | string | TaggedError("OidcUnreachable").message | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1075 |
name | public | string | TaggedError("OidcUnreachable").name | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1074 |
stack? | public | string | TaggedError("OidcUnreachable").stack | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1076 |
Type Aliases
OidcAnswerer
type OidcAnswerer<Pre, O, Needs> = Provider<HttpHandler, ConfigInvalid | OidcUnreachable,
| EnvReading<
| Unpinned<O, "issuer", `${Pre}_ISSUER`>
| Unpinned<O, "clientId", `${Pre}_CLIENT_ID`>
| Unpinned<O, "clientSecret", `${Pre}_CLIENT_SECRET`>
| Unpinned<O, "redirectUri", `${Pre}_REDIRECT_URI`>,
| MaybePinned<O, "issuer", `${Pre}_ISSUER`>
| MaybePinned<O, "clientId", `${Pre}_CLIENT_ID`>
| MaybePinned<O, "clientSecret", `${Pre}_CLIENT_SECRET`>
| MaybePinned<O, "redirectUri", `${Pre}_REDIRECT_URI`>
| Unpinned<O, "postLogoutRedirectUri", `${Pre}_POST_LOGOUT_REDIRECT_URI`>
| MaybePinned<O, "postLogoutRedirectUri", `${Pre}_POST_LOGOUT_REDIRECT_URI`>>
| SessionCodec
| Observers
| Needs
| TokenNeeds<O>> & object;Defined in: packages/http-server/src/oidc.ts:61
The answerer half of what oidc composes — the three login routes as one HttpHandler member. The second half is a CookieSchemes member, which carries no type of its own.
Type Parameters
| Type Parameter | Default type |
|---|---|
Pre extends string | string |
O | OidcPins |
Needs | never |
Type Declaration
| Name | Type | Defined in |
|---|---|---|
port | typeof HttpHandler | packages/http-server/src/oidc.ts:80 |
OidcOptions
type OidcOptions<P, Pre, D> = object;Defined in: packages/http-server/src/oidc.ts:99
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Pre extends string | string |
D extends Readonly<Record<string, AnyPort>> | Record<never, never> |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
allowInsecureIssuer? | readonly | boolean | Talk 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:165 |
clientId? | readonly | string | Pins <prefix>_CLIENT_ID. | packages/http-server/src/oidc.ts:107 |
clientSecret? | readonly | string | Pins <prefix>_CLIENT_SECRET — this is a confidential client. | packages/http-server/src/oidc.ts:109 |
inject? | readonly | D | The services principal reads, as a provider's inject: each port joins the answerer's needs, and is resolved once, as the graph is built. | packages/http-server/src/oidc.ts:138 |
issuer? | readonly | string | Pins <prefix>_ISSUER — the provider, as its discovery document names itself. | packages/http-server/src/oidc.ts:105 |
postLogout? | readonly | `/${string}` | Where a logout lands when the provider advertises no end_session_endpoint. Default /. | packages/http-server/src/oidc.ts:152 |
postLogoutRedirectUri? | readonly | string | Pins <prefix>_POST_LOGOUT_REDIRECT_URI, an absolute HTTP(S) URI registered with the provider. Requires tokens; its server-only ID token is retrieved while revoking credentials. Without a retained hint, logout stays parameterless. | packages/http-server/src/oidc.ts:121 |
prefix? | readonly | `/${string}` | Where the three routes are mounted. Default /auth. | packages/http-server/src/oidc.ts:131 |
principal | readonly | (claims, services) => P | undefined | What the ID token's claims make the caller, given the services inject names — 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:145 |
redirectUri? | readonly | string | Pins <prefix>_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:115 |
scope? | readonly | string | What the authorization request asks for. Default openid. | packages/http-server/src/oidc.ts:133 |
tokens? | readonly | PortClassOf<string, OidcTokensService> | Server-side token manager. Its binding must match this login. | packages/http-server/src/oidc.ts:147 |
variablePrefix? | readonly | Pre | The prefix of the variables this login reads: <prefix>_ISSUER, <prefix>_CLIENT_ID, <prefix>_CLIENT_SECRET and <prefix>_REDIRECT_URI. The optional return URI uses <prefix>_POST_LOGOUT_REDIRECT_URI. Default HTTP_OIDC. A second login names its own — HTTP_OIDC_STAFF — the way a second jwtAuthenticator does. | packages/http-server/src/oidc.ts:129 |
OidcPins
type OidcPins = object;Defined in: packages/http-server/src/oidc.ts:47
What oidc()'s pins are, as their own type: every one may be set.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
clientId? | readonly | string | packages/http-server/src/oidc.ts:49 |
clientSecret? | readonly | string | packages/http-server/src/oidc.ts:50 |
issuer? | readonly | string | packages/http-server/src/oidc.ts:48 |
postLogoutRedirectUri? | readonly | string | packages/http-server/src/oidc.ts:52 |
redirectUri? | readonly | string | packages/http-server/src/oidc.ts:51 |
Functions
oidc()
function oidc<P>(): <D, O>(options) => readonly [OidcAnswerer<PrefixOf<O, "HTTP_OIDC">, O, InstanceType<D[keyof D]>>, AnyProvider];Defined in: packages/http-server/src/oidc.ts:487
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.
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,nonceand where to return to into the five-minute__Host-oidccookie and redirects to the provider.returnis the seamhtmx({ login })writes;asrides through aslogin_hint.GET <prefix>/callbackchecksstateagainst that cookie, exchanges the code, and sealsprincipal(claims)into__Host-session— clearing the transient in the same answer.POST <prefix>/logoutclears the session and sends the browser to the provider'send_session_endpoint, or topostLogoutwhen it advertises none. A configuredpostLogoutRedirectUriadds the registered return and the bound server-side ID-token hint while invalidating credentials atomically.
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.
It answers TWO providers, and the second is why they are spread: the answerer, and a CookieSchemes member, because this is a cookie-reading surface and csrf's default is a fact about the graph rather than a line somebody remembered to write. Without it a root composing oidc() and sessionCodec() but no sessionAuthenticator served a state-changing POST <prefix>/logout over a cookie with CSRF off — the composition the package's own spec called "does not work at all", which nonetheless logs a browser in and exposes the logout. defineHttp already spreads the same member beside a scheme that reads one; this is that rule reaching the one surface it could not see.
Type Parameters
| Type Parameter | Default type |
|---|---|
P | unknown |
Returns
<D, O>(options) => readonly [OidcAnswerer<PrefixOf<O, "HTTP_OIDC">, O, InstanceType<D[keyof D]>>, AnyProvider]