@owlmeans/oidc 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 +15 -12
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/oidc/SKILL.md +72 -27
- package/agent-meta/skills/oidc-versions/SKILL.md +95 -67
- package/build/entrypoints.d.ts +10 -0
- package/build/entrypoints.d.ts.map +1 -0
- package/build/entrypoints.js +10 -0
- package/build/entrypoints.js.map +1 -0
- package/build/guard.d.ts +9 -2
- package/build/guard.d.ts.map +1 -1
- package/build/guard.js +30 -11
- package/build/guard.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/types.d.ts +20 -0
- package/build/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/{modules.ts → entrypoints.ts} +9 -9
- package/src/guard.ts +36 -14
- package/src/index.ts +1 -1
- package/src/types.ts +20 -0
- package/tests/guard.spec.ts +35 -0
- package/tsconfig.json +1 -0
- package/build/.gitkeep +0 -0
- package/build/modules.d.ts +0 -2
- package/build/modules.d.ts.map +0 -1
- package/build/modules.js +0 -9
- package/build/modules.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
# @owlmeans/oidc
|
|
2
2
|
|
|
3
|
-
Shared OIDC protocol abstractions — guard/gate aliases, models, and
|
|
3
|
+
Shared OIDC protocol abstractions — guard/gate aliases, models, and immutable protocol declarations used by both server and browser OIDC packages.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
- `OIDC_GATE` — gate alias to
|
|
7
|
+
- `OIDC_GATE` — gate alias to put in a protocol's `gate` option
|
|
8
8
|
- `OIDC_GUARD`, `WRAPPED_OIDC`, `OIDC_FLOW`, `OIDC_AUTHEN_MODULE`, `OIDC_WRAPPED_TOKEN` — shared aliases
|
|
9
9
|
- `OidcGuard`, `WithSharedConfig`, `OidcProviderConfig` — shared types
|
|
10
|
-
-
|
|
10
|
+
- Entrypoint declarations for the OIDC dispatcher (`/authenticate/oidc/init`, `/authenticate/oidc/process`)
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bun add @owlmeans/oidc
|
|
15
|
+
bun add @owlmeans/oidc@^0.1.18-rc.50
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
19
19
|
|
|
20
|
-
Compose `OIDC_GATE` into a
|
|
20
|
+
Compose `OIDC_GATE` into a protocol declaration:
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
|
-
import {
|
|
23
|
+
import { contract, protocol, typed } from '@owlmeans/entrypoint'
|
|
24
24
|
import { route } from '@owlmeans/route'
|
|
25
25
|
import { DEFAULT_GUARD } from '@owlmeans/auth-common'
|
|
26
26
|
import { OIDC_GATE } from '@owlmeans/oidc'
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
protocol(
|
|
29
29
|
route(manager.back.account.base, '/account'),
|
|
30
|
-
|
|
30
|
+
contract(typed<Account>()),
|
|
31
|
+
{ guards: DEFAULT_GUARD, gate: { alias: OIDC_GATE, params: [`my-service-account-{entity}`] } },
|
|
31
32
|
)
|
|
32
33
|
```
|
|
33
34
|
|
|
@@ -56,7 +57,7 @@ import { OIDC_GUARD } from '@owlmeans/oidc'
|
|
|
56
57
|
- `WRAPPED_OIDC` — `'wrapped-oidc-authz'`
|
|
57
58
|
- `OIDC_AUTHEN_MODULE` — `'iam-oidc-authen'`
|
|
58
59
|
- `OIDC_WRAPPED_TOKEN` — `'oidc-wrapped-token'`
|
|
59
|
-
- `DISPATCHER_OIDC`, `DISPATCHER_OIDC_INIT` — auth dispatcher
|
|
60
|
+
- `DISPATCHER_OIDC`, `DISPATCHER_OIDC_INIT` — auth dispatcher entrypoint aliases
|
|
60
61
|
- `INTERACTION`, `INTERACTION_PATH` — interaction route aliases
|
|
61
62
|
- `OIDC_GUARD_CACHE` — guard cache resource alias
|
|
62
63
|
|
|
@@ -73,9 +74,11 @@ import { OIDC_GUARD } from '@owlmeans/oidc'
|
|
|
73
74
|
- `GOOGLE_CLIENT_AUTH` identifies the browser Google auth plugin registered by `@owlmeans/web-oidc-rp/auth/plugins`.
|
|
74
75
|
- `OIDC_GATE` is for OIDC-backed authorization. Apps that only use Google/OIDC for login and authorize against local identity records should define their own product gate alias.
|
|
75
76
|
|
|
76
|
-
### `
|
|
77
|
+
### `oidcProtocols`
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
Immutable dispatcher declaration tree: `POST /authenticate/oidc/init` and
|
|
80
|
+
`POST /authenticate/oidc/process`. The relying-party packages bind these exact protocol objects
|
|
81
|
+
locally; do not recreate them or consume an alias-addressed compatibility list.
|
|
79
82
|
|
|
80
83
|
## Related Packages
|
|
81
84
|
|
|
@@ -92,7 +95,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
92
95
|
your project's skill store (`.agents/skills/`):
|
|
93
96
|
|
|
94
97
|
```sh
|
|
95
|
-
npx @owlmeans/agent-skills
|
|
98
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.44
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
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/oidc",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.50",
|
|
5
|
+
"generatedAt": "2026-09-30T09:41:02.827Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oidc
|
|
3
|
-
description: How to use @owlmeans/oidc —
|
|
3
|
+
description: How to use @owlmeans/oidc — the OIDC names both sides share — the OIDC_GATE alias, the guard, the requested-scope contract, provider descriptors, the dispatcher entrypoints and the error query params. Auto-invoked when importing OIDC types or constants, wiring OIDC into a protocol gate, or declaring an identity provider in configuration.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,60 +8,105 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/oidc
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/oidc": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/oidc": "^0.1.18-rc.50"` in `dependencies`
|
|
12
|
+
|
|
13
|
+
The shared half of the OIDC stack: no transport, no library. It owns the names, the shapes and the
|
|
14
|
+
guard that the server relying party (`@owlmeans/server-oidc-rp`), the browser relying party
|
|
15
|
+
(`@owlmeans/web-oidc-rp`) and the embedded provider (`@owlmeans/server-oidc-provider`) must agree on.
|
|
12
16
|
|
|
13
17
|
## Key Exports
|
|
14
18
|
|
|
15
19
|
| Export | Description |
|
|
16
20
|
|--------|-------------|
|
|
17
|
-
| `OIDC_GATE` | Gate alias to pass
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
21
|
+
| `OIDC_GATE` | Gate alias to pass in a protocol's `gate` option |
|
|
22
|
+
| `OIDC_GUARD` | The guard's alias |
|
|
23
|
+
| `OIDC_GUARD_CACHE` | A resource-alias constant nothing reads — the guard has no cache lookup, so registering a resource under it changes no behaviour |
|
|
24
|
+
| `makeOidcGuard(opts?)` / `appendOidcGuard(context, opts?)` | The wrapped-token guard, and its registration. The target-specific packages wrap these |
|
|
25
|
+
| `withOidcGuard(protocolTree, coguards?)` | Returns a decorated immutable protocol tree, prepending `OIDC_GUARD` to selected guarded declarations (default `DEFAULT_GUARD`) |
|
|
26
|
+
| `oidcProtocols` | Shared dispatcher declarations: `DISPATCHER_OIDC_INIT` (`POST /authenticate/oidc/init`) and `DISPATCHER_OIDC` (`POST /authenticate/oidc/process`) |
|
|
27
|
+
| `DISPATCHER_OIDC_INIT`, `DISPATCHER_OIDC` | Their aliases |
|
|
28
|
+
| `OIDC_WRAPPED_TOKEN`, `WRAPPED_OIDC` | The authorization-header scheme for an OIDC-wrapped token, and the service alias that refreshes one |
|
|
29
|
+
| `OIDC_CLIENT_AUTH`, `GOOGLE_CLIENT_AUTH` | Authentication plugin types — the generic OIDC one and the Google one |
|
|
30
|
+
| `GOOGLE_SERVICE` | Provider service value for Google (`'google'`) |
|
|
20
31
|
| `OIDC_RP_BASE_SCOPES` / `OIDC_RP_BASE_SCOPE` | The scopes every OwlMeans RP requests, as array / space-delimited string |
|
|
21
|
-
| `EMAIL_SCOPE`, `PERMISSIONS_SCOPE`, `PERMISSIONS_CLAIM` |
|
|
22
|
-
| `OIDC_ERROR_QUERY`, `OIDC_ERROR_DESCRIPTION_QUERY` | Redirect-URI params an authorization server sets on failure |
|
|
23
|
-
| `INTERACTION`, `INTERACTION_PATH`, `INTERACTION_UID` | Interaction screen
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
|
|
|
27
|
-
|
|
|
32
|
+
| `EMAIL_SCOPE`, `PERMISSIONS_SCOPE`, `PERMISSIONS_CLAIM` | The standard email scope; the integrated-IAM grant scope and the claim it produces |
|
|
33
|
+
| `OIDC_CODE_QUERY`, `OIDC_ERROR_QUERY`, `OIDC_ERROR_DESCRIPTION_QUERY` | Redirect-URI params an authorization server sets on success and on failure |
|
|
34
|
+
| `INTERACTION`, `INTERACTION_PATH`, `INTERACTION_UID` | Interaction screen alias, path, and the uid path param the path must declare |
|
|
35
|
+
| `PROVIDER_INTERACTION`, `OIDC_AUTHEN_MODULE`, `OIDC_FLOW` | The provider-side interaction alias, the IAM authentication entrypoint alias, and the flow name |
|
|
36
|
+
| `DEFAULT_PATH`, `DEFAULT_FRONT` | `'oidc'` and `'oidc-client'` — the provider's default base path and the default front service alias |
|
|
37
|
+
| `OidcProviderDescriptor` | One identity provider as configuration: `clientId`, `secret?`, `discoveryUrl?`, `service?`/`basePath?`, `redirectUri?`, `extraScopes?`, `entityId?`, `idOverride?`, the three endpoint overrides `authEndpoint?`/`tokenEndpoint?`/`userinfoEndpoint?`, plus the presentation fields below |
|
|
38
|
+
| `OidcProviderConfig` | A descriptor plus `internal?` (machine use only) and `apiClientId?` (the admin client) |
|
|
39
|
+
| `OidcSharedConfig` / `WithSharedConfig` | `cfg.oidc`: `providers`, `restrictedProviders`, `clientCookie.interaction` |
|
|
40
|
+
| `OidcIamConfig` | `{ iamMode?: 'keycloak' \| 'integrated' }` — the IAM-mode seam, kept here to avoid a cycle with `@owlmeans/iam` |
|
|
41
|
+
| `OidcGuard`, `OidcGuardOptions` | The guard service type, and `{ coguards, cache?, tokenService? }` — only `coguards` (its **first** entry, default `DEFAULT_GUARD`) and `tokenService` are read; `cache` is declared and never used |
|
|
42
|
+
| `OIDCAuthInitParams`, `OIDCClientAuthPayload`, `OIDCTokenUpdate`, `CommonTokenSetParams` | The dispatcher wire shapes |
|
|
43
|
+
| `OIDCAuthInitParamsSchema`, `OIDCClientAuthPayloadSchema`, `OIDCTokenUpdateSchema`, `ProviderProfileDetailsSchema` | Their AJV schemas |
|
|
44
|
+
| `ProviderProfileDetails`, `OidcUserDetails`, `OidcProviderSettings` | What an identity provider reports about a subject |
|
|
45
|
+
| `WrappedOIDCService` | The `AuthorizationService` that keeps a wrapped token fresh |
|
|
28
46
|
|
|
29
47
|
## Usage
|
|
30
48
|
|
|
31
49
|
```typescript
|
|
32
|
-
import {
|
|
50
|
+
import { contract, protocol, typed } from '@owlmeans/entrypoint'
|
|
33
51
|
import { route } from '@owlmeans/route'
|
|
34
52
|
import { DEFAULT_GUARD } from '@owlmeans/auth-common'
|
|
35
53
|
import { OIDC_GATE } from '@owlmeans/oidc'
|
|
36
54
|
|
|
37
|
-
|
|
38
|
-
route(
|
|
39
|
-
|
|
55
|
+
protocol(
|
|
56
|
+
route(accountAlias, '/account'),
|
|
57
|
+
contract(typed<Account>()),
|
|
58
|
+
{ guards: DEFAULT_GUARD, gate: { alias: OIDC_GATE, params: ['my-service-account--read'] } },
|
|
40
59
|
)
|
|
41
60
|
```
|
|
42
61
|
|
|
43
|
-
The
|
|
62
|
+
The verification itself happens in `@owlmeans/server-oidc-rp` (server) and `@owlmeans/web-oidc-rp`
|
|
63
|
+
(browser); this package gives both sides one name to refer to. `OIDC_GATE` is for OIDC/UMA-style
|
|
64
|
+
authorization. A product that authenticates over OIDC but authorizes against its own identity
|
|
65
|
+
resources declares its own gate alias instead.
|
|
44
66
|
|
|
45
67
|
## Scope names are a cross-package contract
|
|
46
68
|
|
|
47
69
|
`OIDC_RP_BASE_SCOPES` is the one definition of what an OwlMeans relying party asks an authorization
|
|
48
|
-
server for
|
|
70
|
+
server for, and two sides read it from here:
|
|
49
71
|
|
|
50
72
|
- the **RP** builds its request from it (`requestedScope()` in `@owlmeans/server-oidc-rp`);
|
|
51
73
|
- whoever **registers the client** must allow at least these scopes — an authorization server
|
|
52
|
-
rejects the entire request with `invalid_scope` when a requested scope is one it supports but
|
|
53
|
-
|
|
74
|
+
rejects the entire request with `invalid_scope` when a requested scope is one it supports but the
|
|
75
|
+
client is not allowed to use.
|
|
54
76
|
|
|
55
|
-
Never hardcode a scope string on either side
|
|
77
|
+
Never hardcode a scope string on either side. Adding one to `OIDC_RP_BASE_SCOPES` must widen every
|
|
56
78
|
client allowlist derived from it in the same change.
|
|
57
79
|
|
|
58
|
-
##
|
|
80
|
+
## Provider descriptors
|
|
81
|
+
|
|
82
|
+
`cfg.oidc.providers` is the list. `discoveryUrl` is the canonical form — the fully-qualified issuer,
|
|
83
|
+
used verbatim; `service` + `basePath` is the legacy fallback that reassembles the issuer from a
|
|
84
|
+
registered service host, and it forces the relying party to know the provider's URL layout.
|
|
85
|
+
|
|
86
|
+
Presentation lives on the descriptor too, because a browser never talks to the issuer directly and
|
|
87
|
+
has no discovery document to read a name out of: `label` (the human-readable name), `icon` (an icon
|
|
88
|
+
registry **name**, never markup), `order` (ascending; absent sorts after the default) and `hidden`
|
|
89
|
+
(registered but never offered). `internal: true` means machine use and is never offered either.
|
|
90
|
+
|
|
91
|
+
`def` marks the default provider, and **both sides read it**. On the server, `getDefault()` in
|
|
92
|
+
`@owlmeans/server-oidc-rp` returns the `clientId` of the first provider carrying the flag, and the
|
|
93
|
+
init handler resolves the OIDC client from that value before it looks at `entityId` at all — so `def`
|
|
94
|
+
in a server config decides which provider the browser-starts-server-finishes flow runs against. In
|
|
95
|
+
the browser it drives presentation as well: `@owlmeans/web-oidc-rp` gives the flagged provider a
|
|
96
|
+
login method of `order` 20 (unless the descriptor sets its own) and renders it with primary emphasis.
|
|
97
|
+
|
|
98
|
+
`restrictedProviders` narrows what an application may use: `false` forbids identity-provider sign-in
|
|
99
|
+
outright, `true` allows only the default one, and an array is an allowlist matched against a
|
|
100
|
+
provider's `entityId ?? service ?? clientId`.
|
|
59
101
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
102
|
+
`authEndpoint`, `tokenEndpoint` and `userinfoEndpoint` name a provider's endpoints outright, for a
|
|
103
|
+
provider reached without discovery. The shipped reader of all three is the Google sign-in plugin in
|
|
104
|
+
`@owlmeans/server-oidc-rp`, which falls back to Google's own endpoints when they are absent; a
|
|
105
|
+
descriptor that carries a `discoveryUrl` gets its endpoints from the discovery document instead and
|
|
106
|
+
these fields do nothing.
|
|
64
107
|
|
|
65
108
|
## Depends On
|
|
66
109
|
|
|
67
|
-
- `@owlmeans/entrypoint`, `@owlmeans/route`, `@owlmeans/auth
|
|
110
|
+
- `@owlmeans/entrypoint`, `@owlmeans/route`, `@owlmeans/auth`, `@owlmeans/auth-common`,
|
|
111
|
+
`@owlmeans/basic-envelope`, `@owlmeans/config`, `@owlmeans/context`, `@owlmeans/resource`
|
|
112
|
+
- `ajv` (peer) — the schemas above are `JSONSchemaType` declarations
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oidc-versions
|
|
3
3
|
description: How to manage and upgrade the four OIDC/OAuth third-party dependencies used by OwlMeans OIDC packages. Covers exact-pin policy, official doc anchors, breaking-change checklists for each lib, the OwlMeans isolation principle, and the verification flow across common and downstream repos. Auto-invoked when touching oidc-provider, openid-client, jose, or oidc-client-ts version strings in package.json files.
|
|
4
|
-
allowed-tools: Bash(npm view *) Bash(grep *) Bash(bun *)
|
|
4
|
+
allowed-tools: Bash(npm view *), Bash(grep *), Bash(bun *)
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
7
|
|
|
8
8
|
# OIDC / OAuth dependency version management — OwlMeans Common
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The sibling of [[versions]] (internal `@owlmeans/*` version sync) and [[shadcn-versions]] (UI lib
|
|
11
|
+
bumps). Use it whenever upgrading the upstream OIDC/OAuth libraries, and cross-read it before
|
|
12
|
+
touching any OIDC package implementation.
|
|
11
13
|
|
|
12
14
|
## The four libraries and their owning packages
|
|
13
15
|
|
|
@@ -18,9 +20,12 @@ This skill is the sibling of [[versions]] (internal `@owlmeans/*` version sync)
|
|
|
18
20
|
| `openid-client` | `@owlmeans/server-oidc-rp` | **exact** | `6.8.4` |
|
|
19
21
|
| `oidc-client-ts` | `@owlmeans/web-oidc-rp`, `@owlmeans/mui-oidc-rp` | **exact** | `3.5.0` |
|
|
20
22
|
|
|
21
|
-
`@types/oidc-provider` is a dev
|
|
23
|
+
`@types/oidc-provider` is a dev dependency of `@owlmeans/server-oidc-provider` and must track the
|
|
24
|
+
oidc-provider major: `9.5.0` (v9 ships no bundled types).
|
|
22
25
|
|
|
23
|
-
All four are authored by panva or authts and follow semantic versioning. **Exact pins** are the
|
|
26
|
+
All four are authored by panva or authts and follow semantic versioning. **Exact pins** are the
|
|
27
|
+
policy — no caret, no range — so that every bump is a deliberate, reviewed change. The pinned value
|
|
28
|
+
lives in each owning package's `dependencies`; nothing else may declare one of these libraries.
|
|
24
29
|
|
|
25
30
|
## Checking installed vs latest
|
|
26
31
|
|
|
@@ -43,91 +48,114 @@ Consult these before every bump — especially for same-major minors that might
|
|
|
43
48
|
|
|
44
49
|
## Breaking-change checklist per library
|
|
45
50
|
|
|
46
|
-
### oidc-provider
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
51
|
+
### oidc-provider v9
|
|
52
|
+
|
|
53
|
+
- **The provider is a Koa app instance**, and `Provider#use(fn)` splices `fn` **ahead of** the
|
|
54
|
+
provider's own router in the Koa chain, so such a middleware runs before routing and resumes
|
|
55
|
+
normally after `await next()`. Header corrections for an OwlMeans server nonetheless belong in a
|
|
56
|
+
middleware registered on the API server **before** `oidc.callback()`, writing to the raw response
|
|
57
|
+
where `@fastify/helmet` has already put its defaults. They must never be a Fastify `onSend` hook:
|
|
58
|
+
`oidc.callback()` ends the response outside Fastify's reply lifecycle, so `onSend` never fires for
|
|
59
|
+
a route the provider answers.
|
|
60
|
+
- **`enableHttpPostMethods` is `false`.** Turning it on requires `cookies.long.sameSite: 'none'` in
|
|
61
|
+
the same configuration; otherwise the constructor throws `TypeError: HTTP POST Method support
|
|
62
|
+
requires that cookies.long.sameSite is set to none`.
|
|
63
|
+
- **DPoP is on.** `features.dPoP.enabled` is `true` with no configuration. Disable it when the
|
|
64
|
+
clients send no DPoP proofs.
|
|
65
|
+
- **Cookie `sameSite` is `lax`** for both `cookies.long` and `cookies.short`. Review it when the
|
|
66
|
+
interaction UI lives on a different subdomain.
|
|
67
|
+
- **JWK `kid` must be unique.** No two keys in `jwks.keys` may share one.
|
|
68
|
+
- **There is no `provider.Account` getter.** Accounts come from the `findAccount` callback.
|
|
69
|
+
- **ESM-only**, and outbound HTTP goes through the `fetch` configuration option — a function
|
|
70
|
+
mirroring the fetch API, defaulting to `globalThis.fetch`. There is no `httpOptions`.
|
|
71
|
+
- **`@types/oidc-provider` must track the major** (`9.5.0`); v9 ships no bundled types.
|
|
72
|
+
|
|
73
|
+
### jose v6
|
|
74
|
+
|
|
75
|
+
- **WebCrypto is the only crypto backend.** `importPKCS8`, `importSPKI` and `importX509` resolve to a
|
|
76
|
+
`CryptoKey`; `importJWK` resolves to a `CryptoKey` for every key type except `oct`, which yields a
|
|
77
|
+
`Uint8Array`. `KeyObject` survives only as an exported type.
|
|
78
|
+
- **`extractable` defaults to `false` for a private key** and `true` for everything else, so an
|
|
79
|
+
imported private key cannot be exported unless the import asked for it:
|
|
67
80
|
```typescript
|
|
68
|
-
// ✅ v6 — must pass { extractable: true }
|
|
69
81
|
const key = await jose.importPKCS8(pkcs8String, 'RS256', { extractable: true })
|
|
70
82
|
const jwk = await jose.exportJWK(key) // works
|
|
71
83
|
```
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
- `decodeJwt(jwt): JWTPayload`.
|
|
85
|
+
- Both the root entry and the subpath entries (`jose/jwt/verify`, `jose/key/import`, `jose/errors`, …)
|
|
86
|
+
are exported. Prefer the root entry — an `import * as jose from 'jose'` is what the OwlMeans
|
|
87
|
+
packages use, and a subpath import buys nothing under a bundler.
|
|
88
|
+
- **CJS `require()` needs Node's `require(esm)` support**; use dynamic `import()` otherwise.
|
|
77
89
|
|
|
78
|
-
|
|
90
|
+
### openid-client v6
|
|
79
91
|
|
|
80
|
-
|
|
81
|
-
- `client.buildAuthorizationUrl(config, params)` — returns a `URL`.
|
|
82
|
-
- `client.authorizationCodeGrant(config, url, checks)` — returns `TokenEndpointResponse`.
|
|
83
|
-
- `client.clientCredentialsGrant(config)` / `client.refreshTokenGrant(config, refreshToken)`.
|
|
84
|
-
- `client.tokenIntrospection(config, token)`.
|
|
85
|
-
- `client.allowInsecureRequests` — passed in the `execute` array option of `discovery` when behind HTTP (dev/internal).
|
|
92
|
+
A functional API — there is no client class. The surface OwlMeans uses:
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
- `discovery(issuerUrl, clientId, metadata?, clientAuthentication?, options?)` → `Configuration`.
|
|
95
|
+
`metadata` accepts the client secret as a bare string. `clientAuthentication` is a `ClientAuth`
|
|
96
|
+
function (`ClientSecretPost(secret)`, `ClientSecretBasic(secret)`, …) and defaults to
|
|
97
|
+
`ClientSecretPost` when a secret is present — passing `undefined` takes that default.
|
|
98
|
+
- `buildAuthorizationUrl(config, params)` → `URL`.
|
|
99
|
+
- `authorizationCodeGrant(config, url, checks)` → `TokenEndpointResponse`.
|
|
100
|
+
- `clientCredentialsGrant(config)` / `refreshTokenGrant(config, refreshToken)`.
|
|
101
|
+
- `tokenIntrospection(config, token)`.
|
|
102
|
+
- `allowInsecureRequests` — passed inside the `execute` array of `discovery`'s options to permit
|
|
103
|
+
plain HTTP for an internal or development issuer.
|
|
88
104
|
|
|
89
|
-
### oidc-client-ts
|
|
105
|
+
### oidc-client-ts v3
|
|
90
106
|
|
|
91
|
-
|
|
107
|
+
Only `UserManager` is referenced, in the incomplete fully-browser-side path; the production flow is a
|
|
108
|
+
server-side token exchange. Check the CHANGELOG for changes to the `UserManager` constructor or
|
|
109
|
+
`signinRedirect` before bumping a minor.
|
|
92
110
|
|
|
93
111
|
## OwlMeans isolation principle
|
|
94
112
|
|
|
95
|
-
**No upstream OIDC library
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- `
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
**No upstream OIDC library NAME may appear in a package's public `index.ts` exports.** Declare
|
|
114
|
+
OwlMeans-owned types and map at the service boundary, so a consumer never imports from
|
|
115
|
+
`openid-client` or `oidc-provider` to type a variable this stack handed it.
|
|
116
|
+
|
|
117
|
+
The public types of `@owlmeans/server-oidc-rp` are the canonical example:
|
|
118
|
+
|
|
119
|
+
- `OidcTokenSet` / `OidcTokenSetParameters` — declared shapes for `access_token`, `refresh_token`,
|
|
120
|
+
`id_token`, `token_type`, `expires_in`, `scope`, with and without the `claims()` helper.
|
|
121
|
+
- `OidcGrantChecks` — the declared shape for PKCE checks.
|
|
122
|
+
- `OidcIntrospectionResponse` — the declared shape for token introspection.
|
|
123
|
+
- `OidcServerMetadata` and `OidcClientDescriptor` — deliberate aliases onto the upstream metadata and
|
|
124
|
+
configuration objects, exported under owned names. `OidcClientDescriptor` is **opaque**: consumers
|
|
125
|
+
receive it and pass it back, and never read its internals.
|
|
126
|
+
|
|
127
|
+
What the principle guarantees is the **exported name**: a consumer types every value this stack hands
|
|
128
|
+
it without importing `openid-client` or `oidc-provider`. It does not confine upstream imports to one
|
|
129
|
+
file, and reading it that way misleads. In `@owlmeans/server-oidc-rp` the type module imports
|
|
130
|
+
`Configuration`, `ServerMetadata`, `TokenEndpointResponse` and `TokenEndpointResponseHelpers` from
|
|
131
|
+
`openid-client` in order to alias them under the owned names; the service module imports the
|
|
132
|
+
functional API; and `jose`'s `decodeJwt` is imported directly by the token wrapper, the `oidc-client`
|
|
133
|
+
auth plugin and the exchange handler. A library swap touches each of those — the owned names are what
|
|
134
|
+
keep it from reaching any consumer.
|
|
105
135
|
|
|
106
136
|
See [[server-oidc-rp]] for the full public surface.
|
|
107
137
|
|
|
108
138
|
## Performing a bump
|
|
109
139
|
|
|
110
|
-
1. **Read the CHANGELOG** for the target version (link above). Enumerate every breaking change
|
|
140
|
+
1. **Read the CHANGELOG** for the target version (link above). Enumerate every breaking change
|
|
141
|
+
against the checklist above.
|
|
111
142
|
2. Update the version string in **each owning package's `package.json`** — exact pins only, no caret.
|
|
112
|
-
3. Update `@types/oidc-provider`
|
|
113
|
-
4.
|
|
114
|
-
5. **Fix
|
|
115
|
-
|
|
116
|
-
|
|
143
|
+
3. Update `@types/oidc-provider` when bumping `oidc-provider` across a major.
|
|
144
|
+
4. Reinstall so the lockfile is regenerated.
|
|
145
|
+
5. **Fix the code** using the checklist — particularly the jose `extractable` argument and the
|
|
146
|
+
placement of the header-correcting middleware for oidc-provider.
|
|
147
|
+
6. Build every affected package, then run its unit tests.
|
|
117
148
|
|
|
118
149
|
## Downstream verification
|
|
119
150
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# per repo: viable, viable-agent, internal
|
|
124
|
-
cd <your-project-root>
|
|
125
|
-
bun install # refresh transitive third-party versions
|
|
126
|
-
bun run build # or per-workspace build command
|
|
127
|
-
bun test # or per-workspace test command
|
|
128
|
-
```
|
|
151
|
+
A project that links these packages as local workspace entries picks up the rebuilt outputs
|
|
152
|
+
automatically, but its own transitive copies of the four libraries do not move on their own. After
|
|
153
|
+
rebuilding, in every consuming project: reinstall, build, and run the tests.
|
|
129
154
|
|
|
130
|
-
|
|
155
|
+
Then check `overrides` (or the equivalent resolution field) in each consuming project's root
|
|
156
|
+
manifest and remove any stale pin of `oidc-provider`, `jose`, `openid-client` or `oidc-client-ts` —
|
|
157
|
+
an override outranks the exact pin the owning package declares, so a forgotten one silently keeps the
|
|
158
|
+
old version installed.
|
|
131
159
|
|
|
132
160
|
## Cross-references
|
|
133
161
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Shared OIDC browser-to-server protocols, bound by the relying-party packages. */
|
|
2
|
+
export declare const oidcProtocols: {
|
|
3
|
+
init: import("@owlmeans/entrypoint").EntrypointProtocol<{
|
|
4
|
+
body: import("./types.js").OIDCAuthInitParams;
|
|
5
|
+
}, any>;
|
|
6
|
+
authenticate: import("@owlmeans/entrypoint").EntrypointProtocol<{
|
|
7
|
+
body: import("./types.js").OIDCClientAuthPayload;
|
|
8
|
+
}, any>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=entrypoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAKA,oFAAoF;AACpF,eAAO,MAAM,aAAa;IACxB,IAAI;;;IAIJ,YAAY;;;CAIb,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { contract, protocol, typed } from '@owlmeans/entrypoint';
|
|
2
|
+
import { route, RouteMethod, backend } from '@owlmeans/route';
|
|
3
|
+
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from './consts.js';
|
|
4
|
+
import { OIDCAuthInitParamsSchema, OIDCClientAuthPayloadSchema } from './models.js';
|
|
5
|
+
/** Shared OIDC browser-to-server protocols, bound by the relying-party packages. */
|
|
6
|
+
export const oidcProtocols = {
|
|
7
|
+
init: protocol(route(DISPATCHER_OIDC_INIT, '/authenticate/oidc/init', backend(null, RouteMethod.POST)), contract.request({ body: typed(OIDCAuthInitParamsSchema) }, typed())),
|
|
8
|
+
authenticate: protocol(route(DISPATCHER_OIDC, '/authenticate/oidc/process', backend(null, RouteMethod.POST)), contract.request({ body: typed(OIDCClientAuthPayloadSchema) }, typed())),
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=entrypoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAEnF,oFAAoF;AACpF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,QAAQ,CACZ,KAAK,CAAC,oBAAoB,EAAE,yBAAyB,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACvF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,wBAAwB,CAAC,EAAE,EAAE,KAAK,EAAO,CAAC,CAC1E;IACD,YAAY,EAAE,QAAQ,CACpB,KAAK,CAAC,eAAe,EAAE,4BAA4B,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,2BAA2B,CAAC,EAAE,EAAE,KAAK,EAAO,CAAC,CAC7E;CACF,CAAA"}
|
package/build/guard.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { Config, Context, OidcGuard, OidcGuardOptions } from './types.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EntrypointTree } from '@owlmeans/entrypoint';
|
|
3
3
|
export declare const makeOidcGuard: (opts?: OidcGuardOptions) => OidcGuard;
|
|
4
4
|
export declare const appendOidcGuard: <C extends Config, T extends Context<C>>(context: T, opts?: OidcGuardOptions) => T;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Decorate an immutable protocol tree so the OIDC guard runs before each selected auth guard.
|
|
7
|
+
*
|
|
8
|
+
* The tree's shape and protocol types are preserved; only declarations that explicitly carry a
|
|
9
|
+
* selected guard are cloned. Parent inheritance then carries OIDC to their children exactly as
|
|
10
|
+
* the route model does for every other guard.
|
|
11
|
+
*/
|
|
12
|
+
export declare const withOidcGuard: <Tree extends EntrypointTree>(tree: Tree, coguards?: string | readonly string[]) => Tree;
|
|
6
13
|
//# sourceMappingURL=guard.d.ts.map
|
package/build/guard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAA;AAGlG,OAAO,KAAK,EAAqC,cAAc,EAAgB,MAAM,sBAAsB,CAAA;AAQ3G,eAAO,MAAM,aAAa,UAAW,gBAAgB,KAAG,SAqGvD,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WAC3D,CAAC,SAAS,gBAAgB,MAKpC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,SAAS,cAAc,QACjD,IAAI,aAAa,MAAM,GAAG,SAAS,MAAM,EAAE,KAChD,IAcF,CAAA"}
|
package/build/guard.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createService } from '@owlmeans/context';
|
|
2
2
|
import { OIDC_GUARD, OIDC_WRAPPED_TOKEN, WRAPPED_OIDC } from './consts.js';
|
|
3
|
+
import { decorateEntrypoint, isEntrypointProtocol } from '@owlmeans/entrypoint';
|
|
3
4
|
import { DEFAULT_GUARD, TOKEN_UPDATE } from '@owlmeans/auth-common';
|
|
4
5
|
import { AUTH_HEADER, AuthorizationError } from '@owlmeans/auth';
|
|
5
6
|
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
|
|
6
7
|
import { trust } from '@owlmeans/auth-common/utils';
|
|
7
8
|
import { TRUSTED } from '@owlmeans/config';
|
|
8
9
|
import { extractAuthToken } from '@owlmeans/auth-common/utils';
|
|
9
|
-
import { modules as oidcModules } from './modules.js';
|
|
10
10
|
export const makeOidcGuard = (opts) => {
|
|
11
11
|
// const cache = (context: Context) => context.hasResource(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
12
12
|
// ? context.resource<Resource<ResourceRecord>>(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
@@ -47,9 +47,19 @@ export const makeOidcGuard = (opts) => {
|
|
|
47
47
|
return false;
|
|
48
48
|
}
|
|
49
49
|
const ctx = guard.assertCtx();
|
|
50
|
-
const envelope = makeEnvelopeModel(authorization, EnvelopeKind.Token);
|
|
51
50
|
const trusted = await trust(ctx, TRUSTED, ctx.cfg.alias ?? ctx.cfg.service);
|
|
52
|
-
|
|
51
|
+
// A token that cannot even be decoded is a credential this server does not accept — the
|
|
52
|
+
// same answer as one whose signature does not verify (401), never a server failure (500).
|
|
53
|
+
let envelope;
|
|
54
|
+
let verified = false;
|
|
55
|
+
try {
|
|
56
|
+
envelope = makeEnvelopeModel(authorization, EnvelopeKind.Token);
|
|
57
|
+
verified = await envelope.verify(trusted.key);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
verified = false;
|
|
61
|
+
}
|
|
62
|
+
if (!verified) {
|
|
53
63
|
return false;
|
|
54
64
|
}
|
|
55
65
|
const token = extractAuthToken(req, OIDC_WRAPPED_TOKEN, false);
|
|
@@ -86,15 +96,24 @@ export const appendOidcGuard = (context, opts) => {
|
|
|
86
96
|
context.registerService(makeOidcGuard(opts));
|
|
87
97
|
return context;
|
|
88
98
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Decorate an immutable protocol tree so the OIDC guard runs before each selected auth guard.
|
|
101
|
+
*
|
|
102
|
+
* The tree's shape and protocol types are preserved; only declarations that explicitly carry a
|
|
103
|
+
* selected guard are cloned. Parent inheritance then carries OIDC to their children exactly as
|
|
104
|
+
* the route model does for every other guard.
|
|
105
|
+
*/
|
|
106
|
+
export const withOidcGuard = (tree, coguards) => {
|
|
107
|
+
const selected = new Set(Array.isArray(coguards) ? coguards : [coguards ?? DEFAULT_GUARD]);
|
|
108
|
+
const decorate = (node) => Object.fromEntries(Object.entries(node).map(([key, value]) => {
|
|
109
|
+
if (!isEntrypointProtocol(value))
|
|
110
|
+
return [key, decorate(value)];
|
|
111
|
+
if (value.guards.includes(OIDC_GUARD) || !value.guards.some(guard => selected.has(guard))) {
|
|
112
|
+
return [key, value];
|
|
96
113
|
}
|
|
97
|
-
|
|
114
|
+
return [key, decorateEntrypoint(value, { guards: [OIDC_GUARD, ...value.guards] })];
|
|
115
|
+
}));
|
|
116
|
+
return decorate(tree);
|
|
98
117
|
};
|
|
99
118
|
const wrapper = (context) => context.hasService(WRAPPED_OIDC)
|
|
100
119
|
? context.service(WRAPPED_OIDC)
|
package/build/guard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,mBAAmB,UAAU,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA"}
|
package/build/types.d.ts
CHANGED
|
@@ -39,6 +39,26 @@ export interface OidcProviderDescriptor {
|
|
|
39
39
|
userinfoEndpoint?: string;
|
|
40
40
|
idOverride?: string;
|
|
41
41
|
def?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Require a live authorization-server decision before accepting a wrapped
|
|
44
|
+
* session. `required` is for applications whose provider is their authority
|
|
45
|
+
* for account disablement and permission changes.
|
|
46
|
+
*/
|
|
47
|
+
sessionValidation?: 'required' | 'optional';
|
|
48
|
+
/**
|
|
49
|
+
* How this provider presents itself on the sign-in screen.
|
|
50
|
+
*
|
|
51
|
+
* A provider list is configuration, so the only place its human-readable name can come from is
|
|
52
|
+
* the configuration itself — the client never talks to the issuer directly and has no discovery
|
|
53
|
+
* document to read a name out of.
|
|
54
|
+
*/
|
|
55
|
+
label?: string;
|
|
56
|
+
/** Icon registry NAME, never markup — this package must stay free of an icon library. */
|
|
57
|
+
icon?: string;
|
|
58
|
+
/** Ascending. Absent means "after the default one". */
|
|
59
|
+
order?: number;
|
|
60
|
+
/** Registered, but never offered as a choice. */
|
|
61
|
+
hidden?: boolean;
|
|
42
62
|
}
|
|
43
63
|
export interface WithSharedConfig {
|
|
44
64
|
oidc: OidcSharedConfig;
|
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,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,MAAM,WAAW,MAAO,SAAQ,WAAW;CAAI;AAC/C,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAC;CAAI;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE;QACb,WAAW,CAAC,EAAE;YACZ,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,GAAG,CAAC,EAAE,MAAM,CAAA;SACb,CAAA;KACF,CAAC;IACF,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAChC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAA;CACzC;AAED,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAEhE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IAErC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,GAAG,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/oidc",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.50",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
25
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/basic-envelope": "^0.1.18-rc.
|
|
27
|
-
"@owlmeans/config": "^0.1.18-rc.
|
|
28
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
29
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
30
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
31
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
24
|
+
"@owlmeans/auth": "^0.1.18-rc.36",
|
|
25
|
+
"@owlmeans/auth-common": "^0.1.18-rc.42",
|
|
26
|
+
"@owlmeans/basic-envelope": "^0.1.18-rc.41",
|
|
27
|
+
"@owlmeans/config": "^0.1.18-rc.39",
|
|
28
|
+
"@owlmeans/context": "^0.1.18-rc.32",
|
|
29
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.37",
|
|
30
|
+
"@owlmeans/resource": "^0.1.18-rc.37",
|
|
31
|
+
"@owlmeans/route": "^0.1.18-rc.33"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"ajv": "*"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contract, protocol, typed } from '@owlmeans/entrypoint'
|
|
2
2
|
import { route, RouteMethod, backend } from '@owlmeans/route'
|
|
3
3
|
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from './consts.js'
|
|
4
4
|
import { OIDCAuthInitParamsSchema, OIDCClientAuthPayloadSchema } from './models.js'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/** Shared OIDC browser-to-server protocols, bound by the relying-party packages. */
|
|
7
|
+
export const oidcProtocols = {
|
|
8
|
+
init: protocol(
|
|
8
9
|
route(DISPATCHER_OIDC_INIT, '/authenticate/oidc/init', backend(null, RouteMethod.POST)),
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
contract.request({ body: typed(OIDCAuthInitParamsSchema) }, typed<any>()),
|
|
11
11
|
),
|
|
12
|
-
|
|
12
|
+
authenticate: protocol(
|
|
13
13
|
route(DISPATCHER_OIDC, '/authenticate/oidc/process', backend(null, RouteMethod.POST)),
|
|
14
|
-
|
|
15
|
-
)
|
|
16
|
-
|
|
14
|
+
contract.request({ body: typed(OIDCClientAuthPayloadSchema) }, typed<any>()),
|
|
15
|
+
),
|
|
16
|
+
}
|
package/src/guard.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createService } from '@owlmeans/context'
|
|
2
2
|
import type { Config, Context, OidcGuard, OidcGuardOptions, WrappedOIDCService } from './types.js'
|
|
3
3
|
import { OIDC_GUARD, OIDC_WRAPPED_TOKEN, WRAPPED_OIDC } from './consts.js'
|
|
4
|
-
import
|
|
4
|
+
import { decorateEntrypoint, isEntrypointProtocol } from '@owlmeans/entrypoint'
|
|
5
|
+
import type { AbstractRequest, AbstractResponse, EntrypointTree, GuardService } from '@owlmeans/entrypoint'
|
|
5
6
|
import { DEFAULT_GUARD, TOKEN_UPDATE } from '@owlmeans/auth-common'
|
|
6
7
|
import { AUTH_HEADER, type Auth, AuthToken, AuthorizationError } from '@owlmeans/auth'
|
|
7
8
|
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
8
9
|
import { trust } from '@owlmeans/auth-common/utils'
|
|
9
10
|
import { TRUSTED } from '@owlmeans/config'
|
|
10
11
|
import { extractAuthToken } from '@owlmeans/auth-common/utils'
|
|
11
|
-
import { modules as oidcModules } from './modules.js'
|
|
12
12
|
|
|
13
13
|
export const makeOidcGuard = (opts?: OidcGuardOptions): OidcGuard => {
|
|
14
14
|
// const cache = (context: Context) => context.hasResource(opts?.cache ?? OIDC_GUARD_CACHE)
|
|
@@ -59,10 +59,19 @@ export const makeOidcGuard = (opts?: OidcGuardOptions): OidcGuard => {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const ctx = guard.assertCtx()
|
|
62
|
-
const envelope = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
63
62
|
const trusted = await trust<Config, Context>(ctx, TRUSTED, ctx.cfg.alias ?? ctx.cfg.service)
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
// A token that cannot even be decoded is a credential this server does not accept — the
|
|
65
|
+
// same answer as one whose signature does not verify (401), never a server failure (500).
|
|
66
|
+
let envelope: ReturnType<typeof makeEnvelopeModel<Auth>>
|
|
67
|
+
let verified = false
|
|
68
|
+
try {
|
|
69
|
+
envelope = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
70
|
+
verified = await envelope.verify(trusted.key)
|
|
71
|
+
} catch {
|
|
72
|
+
verified = false
|
|
73
|
+
}
|
|
74
|
+
if (!verified) {
|
|
66
75
|
return false as T
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -94,7 +103,7 @@ export const makeOidcGuard = (opts?: OidcGuardOptions): OidcGuard => {
|
|
|
94
103
|
|
|
95
104
|
res.resolve(envelope.message())
|
|
96
105
|
} else {
|
|
97
|
-
res.resolve(envelope
|
|
106
|
+
res.resolve(envelope!.message())
|
|
98
107
|
}
|
|
99
108
|
|
|
100
109
|
return true as T
|
|
@@ -112,16 +121,29 @@ export const appendOidcGuard = <C extends Config, T extends Context<C>>(
|
|
|
112
121
|
return context
|
|
113
122
|
}
|
|
114
123
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Decorate an immutable protocol tree so the OIDC guard runs before each selected auth guard.
|
|
126
|
+
*
|
|
127
|
+
* The tree's shape and protocol types are preserved; only declarations that explicitly carry a
|
|
128
|
+
* selected guard are cloned. Parent inheritance then carries OIDC to their children exactly as
|
|
129
|
+
* the route model does for every other guard.
|
|
130
|
+
*/
|
|
131
|
+
export const withOidcGuard = <Tree extends EntrypointTree>(
|
|
132
|
+
tree: Tree, coguards?: string | readonly string[],
|
|
133
|
+
): Tree => {
|
|
134
|
+
const selected = new Set(Array.isArray(coguards) ? coguards : [coguards ?? DEFAULT_GUARD])
|
|
135
|
+
const decorate = (node: EntrypointTree): EntrypointTree => Object.fromEntries(
|
|
136
|
+
Object.entries(node).map(([key, value]) => {
|
|
137
|
+
if (!isEntrypointProtocol(value)) return [key, decorate(value)]
|
|
138
|
+
if (value.guards.includes(OIDC_GUARD) || !value.guards.some(guard => selected.has(guard))) {
|
|
139
|
+
return [key, value]
|
|
140
|
+
}
|
|
118
141
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
})
|
|
142
|
+
return [key, decorateEntrypoint(value, { guards: [OIDC_GUARD, ...value.guards] })]
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return decorate(tree) as Tree
|
|
125
147
|
}
|
|
126
148
|
|
|
127
149
|
const wrapper = (context: Context): WrappedOIDCService =>
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -45,6 +45,26 @@ export interface OidcProviderDescriptor {
|
|
|
45
45
|
idOverride?: string
|
|
46
46
|
// This flag works only on client side. It specifies a default relying party
|
|
47
47
|
def?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* Require a live authorization-server decision before accepting a wrapped
|
|
50
|
+
* session. `required` is for applications whose provider is their authority
|
|
51
|
+
* for account disablement and permission changes.
|
|
52
|
+
*/
|
|
53
|
+
sessionValidation?: 'required' | 'optional'
|
|
54
|
+
/**
|
|
55
|
+
* How this provider presents itself on the sign-in screen.
|
|
56
|
+
*
|
|
57
|
+
* A provider list is configuration, so the only place its human-readable name can come from is
|
|
58
|
+
* the configuration itself — the client never talks to the issuer directly and has no discovery
|
|
59
|
+
* document to read a name out of.
|
|
60
|
+
*/
|
|
61
|
+
label?: string
|
|
62
|
+
/** Icon registry NAME, never markup — this package must stay free of an icon library. */
|
|
63
|
+
icon?: string
|
|
64
|
+
/** Ascending. Absent means "after the default one". */
|
|
65
|
+
order?: number
|
|
66
|
+
/** Registered, but never offered as a choice. */
|
|
67
|
+
hidden?: boolean
|
|
48
68
|
}
|
|
49
69
|
|
|
50
70
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, mock, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A bearer that cannot be decoded is a credential the server does not accept — the guard answers
|
|
5
|
+
* "not authenticated" (the API layer's 401), exactly as for a signature that does not verify, and
|
|
6
|
+
* never throws the decoder's own error (which the API layer answers with 500).
|
|
7
|
+
*/
|
|
8
|
+
mock.module('@owlmeans/auth-common/utils', () => ({
|
|
9
|
+
trust: async () => ({ key: { verify: async () => false } }),
|
|
10
|
+
extractAuthToken: (req: { headers: Record<string, string> }, type: string, strip = true) => {
|
|
11
|
+
const header = req.headers.authorization
|
|
12
|
+
if (header == null || !header.toUpperCase().startsWith(type.toUpperCase())) return null
|
|
13
|
+
return strip ? header.split(' ')[1] : header
|
|
14
|
+
},
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
const { makeOidcGuard } = await import('../src/guard.js')
|
|
18
|
+
|
|
19
|
+
const call = async (authorization: string) => {
|
|
20
|
+
const guard = makeOidcGuard() as any
|
|
21
|
+
guard.assertCtx = () => ({ cfg: { alias: 'app' } })
|
|
22
|
+
const res = { responseProvider: { header: () => undefined } }
|
|
23
|
+
return await guard.handle({ headers: { authorization } }, res)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('oidc guard', () => {
|
|
27
|
+
test('an undecodable wrapped token is unauthenticated, not a server error', async () => {
|
|
28
|
+
expect(await call('OIDC-WRAPPED-TOKEN bogus.token')).toBe(false)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('garbage of every shape stays unauthenticated', async () => {
|
|
32
|
+
expect(await call('OIDC-WRAPPED-TOKEN %%%')).toBe(false)
|
|
33
|
+
expect(await call('OIDC-WRAPPED-TOKEN ')).toBe(false)
|
|
34
|
+
})
|
|
35
|
+
})
|
package/tsconfig.json
CHANGED
package/build/.gitkeep
DELETED
|
File without changes
|
package/build/modules.d.ts
DELETED
package/build/modules.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,OAAO,mDAUnB,CAAA"}
|
package/build/modules.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { body, filter, entrypoint } from '@owlmeans/entrypoint';
|
|
2
|
-
import { route, RouteMethod, backend } from '@owlmeans/route';
|
|
3
|
-
import { DISPATCHER_OIDC, DISPATCHER_OIDC_INIT } from './consts.js';
|
|
4
|
-
import { OIDCAuthInitParamsSchema, OIDCClientAuthPayloadSchema } from './models.js';
|
|
5
|
-
export const modules = [
|
|
6
|
-
entrypoint(route(DISPATCHER_OIDC_INIT, '/authenticate/oidc/init', backend(null, RouteMethod.POST)), filter(body(OIDCAuthInitParamsSchema))),
|
|
7
|
-
entrypoint(route(DISPATCHER_OIDC, '/authenticate/oidc/process', backend(null, RouteMethod.POST)), filter(body(OIDCClientAuthPayloadSchema)))
|
|
8
|
-
];
|
|
9
|
-
//# sourceMappingURL=modules.js.map
|
package/build/modules.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAEnF,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,UAAU,CACR,KAAK,CAAC,oBAAoB,EAAE,yBAAyB,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACvF,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAEvC;IACD,UAAU,CACR,KAAK,CAAC,eAAe,EAAE,4BAA4B,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,EACrF,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAC1C;CACF,CAAA"}
|