@owlmeans/server-oidc-provider 0.1.18-rc.5 → 0.1.18-rc.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-oidc-provider/SKILL.md +148 -40
- package/build/iam.d.ts +2 -29
- package/build/iam.d.ts.map +1 -1
- package/build/iam.js.map +1 -1
- package/build/middleware.d.ts.map +1 -1
- package/build/middleware.js.map +1 -1
- package/build/service.d.ts.map +1 -1
- package/build/service.js +68 -36
- package/build/service.js.map +1 -1
- package/build/types.d.ts +49 -1
- package/build/types.d.ts.map +1 -1
- package/build/utils/config/types.d.ts +11 -0
- package/build/utils/config/types.d.ts.map +1 -0
- package/build/utils/config/types.js +2 -0
- package/build/utils/config/types.js.map +1 -0
- package/build/utils/config.d.ts +5 -3
- package/build/utils/config.d.ts.map +1 -1
- package/build/utils/config.js +86 -40
- package/build/utils/config.js.map +1 -1
- package/build/utils/consts.d.ts +3 -0
- package/build/utils/consts.d.ts.map +1 -0
- package/build/utils/consts.js +3 -0
- package/build/utils/consts.js.map +1 -0
- package/build/utils/index.d.ts +1 -1
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +0 -1
- package/build/utils/index.js.map +1 -1
- package/build/utils/policy.d.ts +24 -0
- package/build/utils/policy.d.ts.map +1 -0
- package/build/utils/policy.js +37 -0
- package/build/utils/policy.js.map +1 -0
- package/package.json +17 -16
- package/src/iam.ts +3 -28
- package/src/middleware.ts +1 -1
- package/src/service.ts +76 -40
- package/src/types.ts +51 -1
- package/src/utils/config/types.ts +11 -0
- package/src/utils/config.ts +101 -42
- package/src/utils/consts.ts +2 -0
- package/src/utils/index.ts +1 -2
- package/src/utils/policy.ts +46 -0
- package/tests/config.spec.ts +59 -6
- package/tests/pairwise.spec.ts +259 -0
- package/tests/policy.spec.ts +216 -0
- package/build/.gitkeep +0 -0
- package/build/utils/client.d.ts +0 -4
- package/build/utils/client.d.ts.map +0 -1
- package/build/utils/client.js +0 -31
- package/build/utils/client.js.map +0 -1
- package/src/utils/client.ts +0 -40
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Embedded OIDC identity provider — wraps the `oidc-provider` library as an OwlM
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
bun add @owlmeans/server-oidc-provider
|
|
17
|
+
bun add @owlmeans/server-oidc-provider@^0.1.18-rc.50
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
@@ -59,7 +59,7 @@ Returns middleware that mounts the OIDC authorize/token/userinfo/jwks endpoints
|
|
|
59
59
|
|
|
60
60
|
## Related Packages
|
|
61
61
|
|
|
62
|
-
- [`@owlmeans/oidc`](../oidc) — shared protocol constants and
|
|
62
|
+
- [`@owlmeans/oidc`](../oidc) — shared protocol constants and entrypoint declarations
|
|
63
63
|
- [`@owlmeans/server-oidc-rp`](../server-oidc-rp) — relying-party counterpart for consuming external IdPs
|
|
64
64
|
- [`@owlmeans/server-api`](../server-api) — the underlying server API the middleware mounts onto
|
|
65
65
|
- [`@owlmeans/web-oidc-provider`](../web-oidc-provider) — browser UI for the provider's interaction screens
|
|
@@ -72,7 +72,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
72
72
|
your project's skill store (`.agents/skills/`):
|
|
73
73
|
|
|
74
74
|
```sh
|
|
75
|
-
npx @owlmeans/agent-skills
|
|
75
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.49
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-oidc-provider",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.50",
|
|
5
|
+
"generatedAt": "2026-10-05T21:03:06.408Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: server-oidc-provider
|
|
3
|
-
description: How to use @owlmeans/server-oidc-provider — embedded OIDC identity provider
|
|
3
|
+
description: How to use @owlmeans/server-oidc-provider — the embedded OIDC identity provider on top of the oidc-provider library — service wiring, the account and adapter seams, the interaction URL, how scopes are derived from claims, the organizations claim, extra discovery fields, pairwise subjects, and the response headers an authorization endpoint has to correct. Auto-invoked when serving OIDC endpoints from your own service.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,66 +8,174 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/server-oidc-provider
|
|
9
9
|
|
|
10
10
|
**Layer:** Server
|
|
11
|
-
**Install:** `"@owlmeans/server-oidc-provider": "^0.1.18-rc.
|
|
12
|
-
**Runtime deps:** `oidc-provider@9.
|
|
11
|
+
**Install:** `"@owlmeans/server-oidc-provider": "^0.1.18-rc.50"` in `dependencies`
|
|
12
|
+
**Runtime deps:** `oidc-provider@9.11.1` (exact), `jose@6.2.5` (exact), `@types/oidc-provider@9.5.0`
|
|
13
|
+
|
|
14
|
+
Use this only when your service **is** the identity provider. For consuming someone else's issuer,
|
|
15
|
+
use `@owlmeans/server-oidc-rp`.
|
|
13
16
|
|
|
14
17
|
## Key Exports
|
|
15
18
|
|
|
16
19
|
| Export | Description |
|
|
17
20
|
|--------|-------------|
|
|
18
|
-
| `createOidcProviderService(alias?)` |
|
|
19
|
-
| `appendOidcProviderService<C,T>(ctx, alias?)` |
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
| `createOidcProviderService(alias?)` | The provider service factory |
|
|
22
|
+
| `appendOidcProviderService<C,T>(ctx, alias?)` | Registers it on a context |
|
|
23
|
+
| `createOidcProviderMiddleware(webAlias?, oidcAlias?)` | Loading-stage middleware that mounts the provider on the API server exactly once. Register it, or nothing is ever mounted |
|
|
24
|
+
| `OidcProviderService` | `instance()`, `update(api)`, `getInteraction(id)` and the live `oidc` provider |
|
|
25
|
+
| `OidcAccountService` | The account seam: `loadById(ctx, id, { clientId? })` — what `findAccount` delegates to |
|
|
26
|
+
| `OidcAdapterService` | The storage seam: `instance(name)` returns an `oidc-provider` `Adapter` |
|
|
27
|
+
| `OIDC_ACCOUNT_SERVICE`, `DEFAULT_ALIAS` | The default account-service alias and the default provider alias |
|
|
28
|
+
| `OidcConfig`, `OidcConfigAppend` | The `cfg.oidc` shape this package reads |
|
|
29
|
+
| `OidcCustomConfiguration` | `oidc-provider`'s `Configuration` plus `sectorIdentifierUriValidate`, which the pinned typings omit — the type of `cfg.oidc.customConfiguration` |
|
|
30
|
+
| `OidcAccountParams` | `{ clientId? }` — lets the account service scope its claims per client |
|
|
31
|
+
| `toClientMetadata(client)` | Maps a stored `OidcRegisteredClient` to `oidc-provider` `ClientMetadata` |
|
|
32
|
+
| `OidcRegisteredClient`, `OidcClientMetadata` | The stored-client shape `toClientMetadata` takes, and the `oidc-provider` metadata shape it returns, carrying `owlEntityId` |
|
|
33
|
+
| `Config`, `Context` | `ServerConfig`/`ServerContext` with `cfg.oidc` and the `debug.oidc` / `debug.oidcServer` / `debug.oidcData` switches |
|
|
34
|
+
|
|
35
|
+
## Wiring
|
|
26
36
|
|
|
27
37
|
```typescript
|
|
28
|
-
import { appendOidcProviderService } from '@owlmeans/server-oidc-provider'
|
|
38
|
+
import { appendOidcProviderService, createOidcProviderMiddleware } from '@owlmeans/server-oidc-provider'
|
|
39
|
+
|
|
29
40
|
appendOidcProviderService<C, T>(context)
|
|
41
|
+
context.registerMiddleware(createOidcProviderMiddleware())
|
|
30
42
|
```
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
`cfg.oidc` supplies `clients` (`ClientMetadata[]`), `defaultKeys.RS256.pk` (a PKCS#8 PEM), and
|
|
45
|
+
optionally `basePath` (default `oidc`), `authService` (whose registered route the issuer is built
|
|
46
|
+
from — defaults to this service), `behindProxy`, `accountService`, `adapterService`,
|
|
47
|
+
`discoveryUris` (below) and `customConfiguration` (merged over the defaults below). The shape also declares `frontBase`, which
|
|
48
|
+
this package reads nowhere — setting it configures nothing.
|
|
49
|
+
|
|
50
|
+
A client's `redirect_uris` and `post_logout_redirect_uris` may be written as `{{service-alias}}/path`
|
|
51
|
+
and are expanded against that registered service's host. `discoveryUris` (field → URL) extends the
|
|
52
|
+
discovery document through the same expansion, merged over `customConfiguration.discovery` — that
|
|
53
|
+
is how a deployment advertises an endpoint another service serves, such as `IAM_API_METADATA`
|
|
54
|
+
(`owlmeans_iam_api`, the runtime IAM API). A field the provider derives itself cannot be overridden
|
|
55
|
+
this way. A client with no `client_secret` is refused
|
|
56
|
+
unless a debug flag is on, in which case one is generated and printed.
|
|
33
57
|
|
|
34
|
-
## Building the interaction URL
|
|
58
|
+
## Building the interaction URL
|
|
35
59
|
|
|
36
60
|
`interactions.url` must return the fully-qualified address of the `INTERACTION` screen, which is a
|
|
37
|
-
**frontend** route resolved from a **server** context. `
|
|
38
|
-
only by `@owlmeans/client-entrypoint` — so the URL is assembled the way
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
**frontend** route resolved from a **server** context. `url()` does not exist there — that helper is
|
|
62
|
+
attached only by `@owlmeans/client-entrypoint` — so the URL is assembled the way the browser's own
|
|
63
|
+
`url()` does it: take the entrypoint's `path()`, substitute the `INTERACTION_UID` path param, then
|
|
64
|
+
`makeSecurityHelper().makeUrl(entry.address(), path)`. `address()` is the address the entrypoint
|
|
65
|
+
answers on — the frontend service's, not this one's — so the base comes from it and must not be
|
|
66
|
+
prepended a second time.
|
|
42
67
|
|
|
43
68
|
## Scopes are derived from `claims`
|
|
44
69
|
|
|
45
|
-
`oidc-provider` adds every key of the `claims` configuration to the supported-scope set
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
`oidc-provider` adds every key of the `claims` configuration to the supported-scope set. Declaring
|
|
71
|
+
`claims.email` therefore makes `email` a **static** scope, and static scopes are checked against each
|
|
72
|
+
client's own `scope` allowlist: a client that omits one fails the whole authorization request with
|
|
73
|
+
`invalid_scope`. Whatever provisions clients for this provider must allow every scope the RP requests
|
|
74
|
+
(`OIDC_RP_BASE_SCOPES`), and the account service must emit the matching claims — a granted scope with
|
|
75
|
+
no claim behind it is silently empty.
|
|
76
|
+
|
|
77
|
+
The defaults this package sets: `claims` covers `email` (`email`, `email_verified`), `profile` (the
|
|
78
|
+
standard set), `PERMISSIONS_SCOPE` → `PERMISSIONS_CLAIM` and `ORGANIZATIONS_SCOPE` →
|
|
79
|
+
`ORGANIZATIONS_CLAIM`, both inert unless the account service actually emits them; `scopes` is
|
|
80
|
+
`openid profile offline_access permissions organizations`; `features.devInteractions` is off.
|
|
81
|
+
Anything under `cfg.oidc.customConfiguration` merges over these.
|
|
82
|
+
|
|
83
|
+
`organizations` is a static scope like any other: only a client whose allowlist names it may ask,
|
|
84
|
+
and a client that does not ask gets no `organizations` claim at all, so a single-organization
|
|
85
|
+
client's tokens never carry one.
|
|
86
|
+
|
|
87
|
+
## Pairwise subjects
|
|
88
|
+
|
|
89
|
+
The integrated IAM gives every client its own subject for one account. `subjectTypes`,
|
|
90
|
+
`pairwiseIdentifier` and `sectorIdentifierUriValidate` pass through `customConfiguration`
|
|
91
|
+
unchanged, and `tests/pairwise.spec.ts` drives the pinned provider through the whole design:
|
|
92
|
+
|
|
93
|
+
- `subjectTypes: ['pairwise']`, `pairwiseIdentifier: (ctx, accountId, client) => <subject>`, and
|
|
94
|
+
`sectorIdentifierUriValidate: () => false`; each client carries `subject_type: 'pairwise'` and
|
|
95
|
+
one constant `sector_identifier_uri` (https, never fetched, so its host may serve nothing — it
|
|
96
|
+
only lets a client register redirect URIs on several hosts).
|
|
97
|
+
- The session and the grant name the ACCOUNT; `findAccount` is only ever asked for the account
|
|
98
|
+
id. The id_token, userinfo and introspection all answer the pairwise subject, unchanged across a
|
|
99
|
+
refresh; another client of the same session gets another one.
|
|
100
|
+
- **The account's `claims()` must return `sub` = the account id.** The provider applies
|
|
101
|
+
`pairwiseIdentifier` to whatever `sub` it is given (`helpers/claims.js`), and introspection to
|
|
102
|
+
`token.accountId` — an account service that returned the pairwise value itself would have it
|
|
103
|
+
transformed a second time, and the id_token would no longer match introspection.
|
|
104
|
+
- With only `pairwise` supported it becomes every client's default `subject_type`; a client
|
|
105
|
+
declaring `public` is refused.
|
|
106
|
+
- `sectorIdentifierUriValidate` is missing from `@types/oidc-provider` 9.5.0, which is why
|
|
107
|
+
`OidcCustomConfiguration` declares it; drop that field when the typings carry it.
|
|
108
|
+
|
|
109
|
+
## oidc-provider v9 configuration
|
|
110
|
+
|
|
111
|
+
- **The provider is a Koa app**, and `Provider#use(fn)` splices `fn` **ahead of** the provider's own
|
|
112
|
+
router, so a middleware registered that way runs before routing and resumes after `await next()`.
|
|
113
|
+
The header corrections below are still mounted on the API server ahead of `oidc.callback()`, for
|
|
114
|
+
the reason given there.
|
|
115
|
+
- **`enableHttpPostMethods` is `false`.** Set it only together with `cookies.long.sameSite: 'none'` —
|
|
116
|
+
the configuration check throws `TypeError: HTTP POST Method support requires that
|
|
117
|
+
cookies.long.sameSite is set to none` otherwise, at construction time.
|
|
118
|
+
- **DPoP is enabled.** Pass `features: { dPoP: { enabled: false } }` when the clients send no DPoP
|
|
119
|
+
proofs.
|
|
120
|
+
- **Cookie `sameSite` is `lax`** for both `cookies.long` and `cookies.short`. Revisit it when the
|
|
121
|
+
interaction UI lives on another subdomain.
|
|
122
|
+
- **Every key in `jwks.keys` needs a distinct `kid`.**
|
|
123
|
+
- There is no `provider.Account` getter — accounts come from the `findAccount` callback, which this
|
|
124
|
+
package points at `OidcAccountService`.
|
|
125
|
+
- Outbound HTTP goes through the `fetch` configuration option, which mirrors the fetch API.
|
|
126
|
+
|
|
127
|
+
## jose v6 key import
|
|
128
|
+
|
|
129
|
+
`importPKCS8` returns a **non-extractable** `CryptoKey` for a private key. Pass `{ extractable: true }`
|
|
130
|
+
so the JWKS export succeeds:
|
|
64
131
|
|
|
65
132
|
```typescript
|
|
66
133
|
const key = await jose.importPKCS8(pkcs8Pem, 'RS256', { extractable: true })
|
|
67
134
|
const jwk = await jose.exportJWK(key)
|
|
68
135
|
```
|
|
69
136
|
|
|
137
|
+
## A refused account is a login, not a crash
|
|
138
|
+
|
|
139
|
+
`loadById` answering `undefined` refuses an account (another organization's subject, a disabled or
|
|
140
|
+
expired profile). The provider does not treat that as "not logged in": its `no_session` check reads
|
|
141
|
+
the raw `session.accountId`, so the login prompt is skipped, `loadGrant` builds no grant for an
|
|
142
|
+
unloaded account, and the consent prompt throws `TypeError … oidc.grant.getOIDCScopeEncountered` — the
|
|
143
|
+
relying party gets `server_error` / "oops! something went wrong".
|
|
144
|
+
|
|
145
|
+
The service therefore installs `makeInteractionPolicy()` (`src/utils/policy.ts`) as
|
|
146
|
+
`interactions.policy`: the provider's default policy plus an `account_refused` check on the login
|
|
147
|
+
prompt that requests a login whenever the session names an account the provider could not load. After
|
|
148
|
+
that login the provider's resume step signs the stale session out and continues the interrupted
|
|
149
|
+
request. A login that has just completed and is refused again (`oidc.result.login`) throws
|
|
150
|
+
`access_denied` instead of prompting, so a refusal can never loop. A consumer's own
|
|
151
|
+
`customConfiguration.interactions` is not merged — the service sets `policy` and `url` itself.
|
|
152
|
+
`tests/policy.spec.ts` drives a real provider through the whole sequence, including the upstream
|
|
153
|
+
crash as a canary: when a bump of `oidc-provider` makes that first test fail, the upstream fixed it
|
|
154
|
+
and the check may go.
|
|
155
|
+
|
|
156
|
+
## Response headers the hardened defaults get wrong
|
|
157
|
+
|
|
158
|
+
`@fastify/helmet` runs with its defaults on every OwlMeans server, and two of them break an
|
|
159
|
+
authorization endpoint. Both are corrected by middleware this package mounts ahead of the provider.
|
|
160
|
+
|
|
161
|
+
- **`Cross-Origin-Opener-Policy: same-origin`** puts the authorization document in a fresh browsing
|
|
162
|
+
context group, severing `window.opener` **permanently** — navigating back to the relying party
|
|
163
|
+
afterwards does not restore it. That kills popup-based login, which is how an app embedded in an
|
|
164
|
+
iframe must authenticate (see the `web-oidc-rp` skill). The provider sends `unsafe-none`.
|
|
165
|
+
- **`form-action 'self'`** blocks the provider's own interaction form posting across origins, so it
|
|
166
|
+
is rewritten to `form-action *`.
|
|
167
|
+
|
|
168
|
+
**Set these as middleware, never as a Fastify `onSend` hook.** `oidc.callback()` is a Koa handler
|
|
169
|
+
mounted through Middie: it ends the response itself, outside Fastify's reply lifecycle, so `onSend`
|
|
170
|
+
never fires for any route the provider answers and anything set there silently never reaches the
|
|
171
|
+
wire — the header looks configured in code and is absent in production. Middleware registered before
|
|
172
|
+
the provider writes to the raw response, where helmet has already put its defaults, so the override
|
|
173
|
+
is what ships. Verify with `curl -D -` against the provider's
|
|
174
|
+
`.well-known/openid-configuration` rather than by reading the code.
|
|
175
|
+
|
|
70
176
|
## Depends On
|
|
71
177
|
|
|
72
|
-
- `@owlmeans/oidc`, `@owlmeans/server-api`, `@owlmeans/server-context
|
|
73
|
-
|
|
178
|
+
- `@owlmeans/oidc`, `@owlmeans/server-api`, `@owlmeans/server-context`, `@owlmeans/config`,
|
|
179
|
+
`@owlmeans/context`, `@owlmeans/entrypoint`, `@owlmeans/route`, `@noble/hashes`, `@scure/base`
|
|
180
|
+
- `fastify` (peer) — the API server this package mounts the provider onto
|
|
181
|
+
- `oidc-provider` v9, `jose` v6 — see [[oidc-versions]] for the pins and the upgrade checklist
|
package/build/iam.d.ts
CHANGED
|
@@ -1,31 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/** A registered OIDC client stored in the provider's Client adapter. */
|
|
3
|
-
export interface OidcRegisteredClient {
|
|
4
|
-
clientId: string;
|
|
5
|
-
secret: string;
|
|
6
|
-
/** The entity (realm) this client belongs to — used for identity scoping. */
|
|
7
|
-
entityId?: string;
|
|
8
|
-
/** Application display name */
|
|
9
|
-
name?: string;
|
|
10
|
-
redirectUris?: string[];
|
|
11
|
-
grantTypes?: string[];
|
|
12
|
-
responseTypes?: string[];
|
|
13
|
-
scope?: string;
|
|
14
|
-
}
|
|
15
|
-
/** Full oidc-provider ClientMetadata with our entity extension. */
|
|
16
|
-
export type OidcClientMetadata = ClientMetadata & {
|
|
17
|
-
entityId?: string;
|
|
18
|
-
owlEntityId?: string;
|
|
19
|
-
};
|
|
1
|
+
import type { ToClientMetadata } from './types.js';
|
|
20
2
|
/** Convert an OidcRegisteredClient to the oidc-provider ClientMetadata shape. */
|
|
21
|
-
export declare const toClientMetadata:
|
|
22
|
-
/** Extension seam for IAM integration into the OIDC provider — Phase 2 fills this */
|
|
23
|
-
export interface OidcProviderIamExtension {
|
|
24
|
-
/** Convert a stored client record to oidc-provider ClientMetadata */
|
|
25
|
-
toClientMetadata: typeof toClientMetadata;
|
|
26
|
-
/** Type of a stored client record */
|
|
27
|
-
OidcRegisteredClient: OidcRegisteredClient;
|
|
28
|
-
/** Extended metadata type */
|
|
29
|
-
OidcClientMetadata: OidcClientMetadata;
|
|
30
|
-
}
|
|
3
|
+
export declare const toClientMetadata: ToClientMetadata;
|
|
31
4
|
//# sourceMappingURL=iam.d.ts.map
|
package/build/iam.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iam.d.ts","sourceRoot":"","sources":["../src/iam.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"iam.d.ts","sourceRoot":"","sources":["../src/iam.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA4C,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE5F,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,EAAE,gBAS7B,CAAA"}
|
package/build/iam.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iam.js","sourceRoot":"","sources":["../src/iam.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"iam.js","sourceRoot":"","sources":["../src/iam.ts"],"names":[],"mappings":"AAGA,iFAAiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAqB,CAAC,MAA4B,EAAsB,EAAE,CAAC,CAAC;IACvG,SAAS,EAAE,MAAM,CAAC,QAAQ;IAC1B,aAAa,EAAE,MAAM,CAAC,MAAM;IAC5B,aAAa,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;IACxC,WAAW,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC,oBAAoB,EAAE,eAAe,CAAC;IACzE,cAAc,EAAE,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,CAAmB;IACpE,0BAA0B,EAAE,qBAAqB;IACjD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,+BAA+B;IACtD,WAAW,EAAE,MAAM,CAAC,QAAQ;CAC7B,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAOnD,eAAO,MAAM,4BAA4B,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAOnD,eAAO,MAAM,4BAA4B,SAAS,MAAM,SAAoB,MAAM,KAAmB,UAqBpG,CAAA"}
|
package/build/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClF,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,GAAW,SAAS,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClF,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,GAAW,SAAS,EAAE,IAAI,GAAW,aAAa,EAAc,EAAE;IAChH,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,cAAc,CAAC,OAAO;QAC5B,KAAK,EAAE,eAAe,CAAC,OAAO;QAC9B,KAAK,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACjB,MAAM,OAAO,GAAG,aAAa,CAAkB,GAAyB,CAAY,CAAA;YACpF,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAY,GAAG,CAAC,CAAA;YAClD,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAsB,IAAI,CAAC,CAAA;YAE9D,MAAM,MAAM,GAAG,sBAAsB,GAAG,IAAI,IAAI,EAAE,CAAA;YAClD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;gBAC3D,MAAM,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBACpC,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;oBAC5B,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAA;gBACtB,CAAC;gBACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;KACF,CAAA;IAED,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA"}
|
package/build/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAA0C,mBAAmB,EAAE,MAAM,YAAY,CAAA;AA2C9G,eAAO,MAAM,yBAAyB,WAAW,MAAM,KAAmB,mBAqGzE,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OACzE,CAAC,UAAS,MAAM,KACpB,CAOF,CAAA"}
|
package/build/service.js
CHANGED
|
@@ -2,9 +2,38 @@ import { assertContext, createService } from '@owlmeans/context';
|
|
|
2
2
|
import { DEFAULT_ALIAS, OIDC_ACCOUNT_SERVICE } from './consts.js';
|
|
3
3
|
import { DEFAULT_PATH, INTERACTION, INTERACTION_UID } from '@owlmeans/oidc';
|
|
4
4
|
import Provider from 'oidc-provider';
|
|
5
|
+
import { logger } from '@owlmeans/log';
|
|
5
6
|
import { PARAM, SEP } from '@owlmeans/route';
|
|
6
7
|
import { makeSecurityHelper } from '@owlmeans/config';
|
|
7
|
-
import {
|
|
8
|
+
import { oidcConfigOf } from './utils/config.js';
|
|
9
|
+
import { makeInteractionPolicy } from './utils/policy.js';
|
|
10
|
+
const log = logger('server-oidc-provider');
|
|
11
|
+
/** An OIDC error the provider answers with a 4xx — the client's mistake, not the provider's. */
|
|
12
|
+
const isClientError = (error) => {
|
|
13
|
+
const status = error?.status;
|
|
14
|
+
return typeof status === 'number' && status >= 400 && status < 500;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* One provider error. The state dump carries ids only — never a token, code or secret the
|
|
18
|
+
* request holds.
|
|
19
|
+
*/
|
|
20
|
+
const reportProviderError = (issuer, kind, ctx, error) => {
|
|
21
|
+
const state = ctx?.oidc;
|
|
22
|
+
const data = { kind, issuer, clientId: state?.client?.clientId, code: error.error, error };
|
|
23
|
+
if (isClientError(error)) {
|
|
24
|
+
log.warn('OIDC provider refused a request', data);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
log.error('OIDC provider error', data);
|
|
28
|
+
}
|
|
29
|
+
if (state != null && log.enabled('debug')) {
|
|
30
|
+
log.debug('OIDC provider error state', {
|
|
31
|
+
kind, fields: Object.getOwnPropertyNames(state),
|
|
32
|
+
grant: state.grant != null
|
|
33
|
+
? { grantId: state.grant.jti, accountId: state.grant.accountId, clientId: state.grant.clientId } : undefined,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
8
37
|
let _initializedOidc = undefined;
|
|
9
38
|
export const createOidcProviderService = (alias = DEFAULT_ALIAS) => {
|
|
10
39
|
const service = createService(alias, {
|
|
@@ -16,7 +45,7 @@ export const createOidcProviderService = (alias = DEFAULT_ALIAS) => {
|
|
|
16
45
|
const url = helper.makeUrl(serviceRoute, cfg.basePath ?? DEFAULT_PATH, { base: true });
|
|
17
46
|
const unsecure = context.cfg.security?.unsecure === false ? false : !url.startsWith('https');
|
|
18
47
|
const oidc = new Provider(url, {
|
|
19
|
-
...await combineConfig(
|
|
48
|
+
...await oidcConfigOf(context).combineConfig(unsecure),
|
|
20
49
|
adapter: cfg.adapterService != null
|
|
21
50
|
? name => context.service(cfg.adapterService).instance(name)
|
|
22
51
|
: undefined,
|
|
@@ -27,53 +56,56 @@ export const createOidcProviderService = (alias = DEFAULT_ALIAS) => {
|
|
|
27
56
|
return accountSrv.loadById(context, id, { clientId });
|
|
28
57
|
},
|
|
29
58
|
interactions: {
|
|
59
|
+
policy: makeInteractionPolicy(),
|
|
30
60
|
url: async (_, interaction) => {
|
|
31
61
|
// The interaction screen is a FRONTEND route, and this is a server context — the
|
|
32
|
-
// entrypoint registered here has no `
|
|
33
|
-
// `@owlmeans/client-entrypoint` only). So the URL is assembled the way `
|
|
34
|
-
// it in the browser:
|
|
35
|
-
// with the
|
|
62
|
+
// entrypoint registered here has no `url()` (that helper is attached by
|
|
63
|
+
// `@owlmeans/client-entrypoint` only). So the URL is assembled the way `entrypointUrl`
|
|
64
|
+
// does it in the browser: take the entrypoint's path, substitute the path params, then
|
|
65
|
+
// qualify it with the address the entrypoint answers on — the FRONTEND service's, not
|
|
66
|
+
// this one's.
|
|
36
67
|
const entry = context.entrypoint(INTERACTION);
|
|
37
|
-
const
|
|
38
|
-
const path = entry.getPath().split(SEP)
|
|
68
|
+
const path = entry.path().split(SEP)
|
|
39
69
|
.map(part => part === `${PARAM}${INTERACTION_UID}` ? interaction.uid : part)
|
|
40
70
|
.join(SEP);
|
|
41
|
-
return helper.makeUrl(
|
|
71
|
+
return helper.makeUrl(entry.address(), path);
|
|
42
72
|
}
|
|
43
73
|
}
|
|
44
74
|
});
|
|
45
75
|
oidc.proxy = cfg.behindProxy ?? unsecure;
|
|
46
76
|
const base = SEP + (cfg.basePath ?? DEFAULT_PATH);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Response headers the hardened defaults get wrong for an authorization endpoint.
|
|
79
|
+
*
|
|
80
|
+
* This runs as middleware, ahead of the provider in the same chain, and writes to the raw
|
|
81
|
+
* response — deliberately, not as a Fastify `onSend` hook. `oidc.callback()` is a Koa
|
|
82
|
+
* handler mounted through Middie: it ends the response itself, outside Fastify's reply
|
|
83
|
+
* lifecycle, so `onSend` never fires for any route the provider answers and anything set
|
|
84
|
+
* there silently never reaches the wire. The security defaults are already on the raw
|
|
85
|
+
* response by this point (`@fastify/helmet` applies them in `onRequest`), so overriding
|
|
86
|
+
* them here is what actually takes effect.
|
|
87
|
+
*/
|
|
88
|
+
api.server.use(base, (_req, res, next) => {
|
|
89
|
+
// `Cross-Origin-Opener-Policy: same-origin` puts this document in a fresh browsing
|
|
90
|
+
// context group, which severs `window.opener` **permanently** — navigating back to the
|
|
91
|
+
// relying party afterwards does not restore it. Popup-based login is the standard way an
|
|
92
|
+
// embedded application authenticates and the opener is its only channel home, so an
|
|
93
|
+
// authorization endpoint must not be the thing that cuts it.
|
|
94
|
+
res.setHeader('Cross-Origin-Opener-Policy', 'unsafe-none');
|
|
95
|
+
// The provider posts its own interaction forms across origins; `form-action 'self'`
|
|
96
|
+
// would block the submission.
|
|
97
|
+
const csp = res.getHeader('Content-Security-Policy');
|
|
55
98
|
if (typeof csp === 'string' && csp.includes("form-action 'self'")) {
|
|
56
|
-
|
|
99
|
+
res.setHeader('Content-Security-Policy', csp.replace(/form-action 'self'/, 'form-action *'));
|
|
57
100
|
}
|
|
58
|
-
|
|
101
|
+
next();
|
|
59
102
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
oidc.on('server_error', (ctx, error) => {
|
|
67
|
-
console.warn('SERVER ERROR .......: ', Object.getOwnPropertyNames(ctx.oidc));
|
|
68
|
-
console.info(ctx.oidc.grant);
|
|
69
|
-
console.error('!!!! SERVER ERROR: ', error);
|
|
70
|
-
});
|
|
71
|
-
oidc.on('userinfo.error', (ctx, error) => {
|
|
72
|
-
console.warn('USER INFO ERROR .......: ', Object.getOwnPropertyNames(ctx.oidc));
|
|
73
|
-
console.info(ctx.oidc.grant);
|
|
74
|
-
console.error('!!!! USER INFO ERROR: ', error);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
103
|
+
api.server.use(base, oidc.callback());
|
|
104
|
+
// Always attached: a provider error reaches the log — at `warn` when the client caused it
|
|
105
|
+
// (an OIDC 4xx such as `invalid_grant`), at `error` otherwise; the request state at `debug`.
|
|
106
|
+
oidc.on('grant.error', (ctx, error) => { reportProviderError(oidc.issuer, 'grant', ctx, error); });
|
|
107
|
+
oidc.on('server_error', (ctx, error) => { reportProviderError(oidc.issuer, 'server', ctx, error); });
|
|
108
|
+
oidc.on('userinfo.error', (ctx, error) => { reportProviderError(oidc.issuer, 'userinfo', ctx, error); });
|
|
77
109
|
_initializedOidc = service.oidc = oidc;
|
|
78
110
|
},
|
|
79
111
|
instance: () => {
|
package/build/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
CHANGED
|
@@ -17,7 +17,14 @@ export interface OidcConfig extends OidcSharedConfig {
|
|
|
17
17
|
basePath?: string;
|
|
18
18
|
frontBase?: string;
|
|
19
19
|
clients: ClientMetadata[];
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Extra fields of the discovery document, field name → URL. A value may be written as
|
|
22
|
+
* `{{service-alias}}/path`, expanded against that registered service's host exactly as a
|
|
23
|
+
* client's redirect URIs are — which is how a deployment advertises an endpoint it serves on
|
|
24
|
+
* another service (`IAM_API_METADATA`).
|
|
25
|
+
*/
|
|
26
|
+
discoveryUris?: Record<string, string>;
|
|
27
|
+
customConfiguration?: OidcCustomConfiguration;
|
|
21
28
|
behindProxy?: boolean;
|
|
22
29
|
defaultKeys: {
|
|
23
30
|
RS256: {
|
|
@@ -28,6 +35,16 @@ export interface OidcConfig extends OidcSharedConfig {
|
|
|
28
35
|
accountService?: string;
|
|
29
36
|
adapterService?: string;
|
|
30
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* The provider configuration a deployment passes through, merged over this package's defaults.
|
|
40
|
+
*
|
|
41
|
+
* Adds what the pinned `@types/oidc-provider` omits but `oidc-provider` reads:
|
|
42
|
+
* `sectorIdentifierUriValidate` answering `false` keeps the provider from fetching a pairwise
|
|
43
|
+
* client's `sector_identifier_uri` — a constant sector whose host serves nothing.
|
|
44
|
+
*/
|
|
45
|
+
export interface OidcCustomConfiguration extends Configuration {
|
|
46
|
+
sectorIdentifierUriValidate?: (client: InstanceType<Provider['Client']>) => boolean;
|
|
47
|
+
}
|
|
31
48
|
export interface OidcAccountParams {
|
|
32
49
|
/** The OIDC client requesting the account — lets the account service scope claims (e.g. permissions) per client. */
|
|
33
50
|
clientId?: string;
|
|
@@ -47,4 +64,35 @@ export interface Config extends ServerConfig, OidcConfigAppend {
|
|
|
47
64
|
}
|
|
48
65
|
export interface Context<C extends Config = Config> extends ServerContext<C>, ApiServerAppend {
|
|
49
66
|
}
|
|
67
|
+
/** A registered OIDC client stored in the provider's Client adapter. */
|
|
68
|
+
export interface OidcRegisteredClient {
|
|
69
|
+
clientId: string;
|
|
70
|
+
secret: string;
|
|
71
|
+
/** The entity (realm) this client belongs to — used for identity scoping. */
|
|
72
|
+
entityId?: string;
|
|
73
|
+
/** Application display name */
|
|
74
|
+
name?: string;
|
|
75
|
+
redirectUris?: string[];
|
|
76
|
+
grantTypes?: string[];
|
|
77
|
+
responseTypes?: string[];
|
|
78
|
+
scope?: string;
|
|
79
|
+
}
|
|
80
|
+
/** Full oidc-provider ClientMetadata with our entity extension. */
|
|
81
|
+
export interface OidcClientMetadata extends ClientMetadata {
|
|
82
|
+
entityId?: string;
|
|
83
|
+
owlEntityId?: string;
|
|
84
|
+
}
|
|
85
|
+
/** Converts a stored client record to oidc-provider ClientMetadata. */
|
|
86
|
+
export interface ToClientMetadata {
|
|
87
|
+
(client: OidcRegisteredClient): OidcClientMetadata;
|
|
88
|
+
}
|
|
89
|
+
/** Extension seam for IAM integration into the OIDC provider — Phase 2 fills this */
|
|
90
|
+
export interface OidcProviderIamExtension {
|
|
91
|
+
/** Convert a stored client record to oidc-provider ClientMetadata */
|
|
92
|
+
toClientMetadata: ToClientMetadata;
|
|
93
|
+
/** Type of a stored client record */
|
|
94
|
+
OidcRegisteredClient: OidcRegisteredClient;
|
|
95
|
+
/** Extended metadata type */
|
|
96
|
+
OidcClientMetadata: OidcClientMetadata;
|
|
97
|
+
}
|
|
50
98
|
//# sourceMappingURL=types.d.ts.map
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE3G,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,IAAI,EAAE,QAAQ,CAAA;IAEd,MAAM,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,QAAQ,EAAE,MAAM,QAAQ,CAAA;IAExB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IACjF,IAAI,EAAE,UAAU,GAAG,KAAK,CAAA;CACzB;AAED,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,mBAAmB,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { OidcCustomConfiguration } from '../../types.js';
|
|
2
|
+
/** The provider configuration one context's settings resolve to. */
|
|
3
|
+
export interface OidcConfigUtils {
|
|
4
|
+
/**
|
|
5
|
+
* The deployment's configuration merged over this package's defaults: its clients with their
|
|
6
|
+
* `{{service-alias}}` URIs expanded (and, in debug only, a generated secret), the claims behind
|
|
7
|
+
* every scope, the discovery extras and the signing key.
|
|
8
|
+
*/
|
|
9
|
+
combineConfig: (unsecure: boolean) => Promise<OidcCustomConfiguration>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE7D,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,aAAa,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAA;CACvE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/config/types.ts"],"names":[],"mappings":""}
|
package/build/utils/config.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { Context } from '../types.js';
|
|
2
|
-
import type {
|
|
3
|
-
export declare const
|
|
1
|
+
import type { Config, Context } from '../types.js';
|
|
2
|
+
import type { OidcConfigUtils } from './config/types.js';
|
|
3
|
+
export declare const makeOidcConfigUtils: (context: Context) => OidcConfigUtils;
|
|
4
|
+
/** The configuration utils of a context — one per context. */
|
|
5
|
+
export declare const oidcConfigOf: (target: Context<Config>) => OidcConfigUtils;
|
|
4
6
|
//# sourceMappingURL=config.d.ts.map
|