@owlmeans/server-auth-token 0.1.18-rc.8 → 0.1.18

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.
Files changed (79) hide show
  1. package/README.md +177 -1
  2. package/agent-meta/manifest.json +3 -3
  3. package/agent-meta/skills/server-auth-token/SKILL.md +33 -10
  4. package/build/guard.d.ts +1 -3
  5. package/build/guard.d.ts.map +1 -1
  6. package/build/guard.js +37 -14
  7. package/build/guard.js.map +1 -1
  8. package/build/handlers/create.d.ts +5 -0
  9. package/build/handlers/create.d.ts.map +1 -0
  10. package/build/handlers/create.js +18 -0
  11. package/build/handlers/create.js.map +1 -0
  12. package/build/handlers/index.d.ts +11 -11
  13. package/build/handlers/index.d.ts.map +1 -1
  14. package/build/handlers/index.js +8 -93
  15. package/build/handlers/index.js.map +1 -1
  16. package/build/handlers/issue.d.ts +6 -0
  17. package/build/handlers/issue.d.ts.map +1 -0
  18. package/build/handlers/issue.js +42 -0
  19. package/build/handlers/issue.js.map +1 -0
  20. package/build/handlers/list.d.ts +3 -0
  21. package/build/handlers/list.d.ts.map +1 -0
  22. package/build/handlers/list.js +18 -0
  23. package/build/handlers/list.js.map +1 -0
  24. package/build/handlers/refuse.d.ts +19 -0
  25. package/build/handlers/refuse.d.ts.map +1 -0
  26. package/build/handlers/refuse.js +20 -0
  27. package/build/handlers/refuse.js.map +1 -0
  28. package/build/handlers/revoke.d.ts +17 -0
  29. package/build/handlers/revoke.d.ts.map +1 -0
  30. package/build/handlers/revoke.js +35 -0
  31. package/build/handlers/revoke.js.map +1 -0
  32. package/build/handlers/types.d.ts +37 -0
  33. package/build/handlers/types.d.ts.map +1 -0
  34. package/build/handlers/types.js +2 -0
  35. package/build/handlers/types.js.map +1 -0
  36. package/build/handlers/utils/types.d.ts +10 -0
  37. package/build/handlers/utils/types.d.ts.map +1 -0
  38. package/build/handlers/utils/types.js +2 -0
  39. package/build/handlers/utils/types.js.map +1 -0
  40. package/build/handlers/utils.d.ts +4 -0
  41. package/build/handlers/utils.d.ts.map +1 -0
  42. package/build/handlers/utils.js +11 -0
  43. package/build/handlers/utils.js.map +1 -0
  44. package/build/hash/types.d.ts +16 -0
  45. package/build/hash/types.d.ts.map +1 -0
  46. package/build/hash/types.js +2 -0
  47. package/build/hash/types.js.map +1 -0
  48. package/build/hash.d.ts +4 -15
  49. package/build/hash.d.ts.map +1 -1
  50. package/build/hash.js +13 -16
  51. package/build/hash.js.map +1 -1
  52. package/build/index.d.ts +3 -0
  53. package/build/index.d.ts.map +1 -1
  54. package/build/index.js +1 -0
  55. package/build/index.js.map +1 -1
  56. package/build/prefix.d.ts +4 -0
  57. package/build/prefix.d.ts.map +1 -0
  58. package/build/prefix.js +4 -0
  59. package/build/prefix.js.map +1 -0
  60. package/build/types.d.ts +20 -0
  61. package/build/types.d.ts.map +1 -1
  62. package/package.json +17 -16
  63. package/src/guard.ts +39 -16
  64. package/src/handlers/create.ts +21 -0
  65. package/src/handlers/index.ts +17 -115
  66. package/src/handlers/issue.ts +50 -0
  67. package/src/handlers/list.ts +21 -0
  68. package/src/handlers/refuse.ts +20 -0
  69. package/src/handlers/revoke.ts +42 -0
  70. package/src/handlers/types.ts +40 -0
  71. package/src/handlers/utils/types.ts +10 -0
  72. package/src/handlers/utils.ts +18 -0
  73. package/src/hash/types.ts +16 -0
  74. package/src/hash.ts +17 -21
  75. package/src/index.ts +3 -0
  76. package/src/prefix.ts +6 -0
  77. package/src/types.ts +21 -0
  78. package/tests/guard.spec.ts +54 -10
  79. package/tests/handlers.spec.ts +56 -8
package/README.md CHANGED
@@ -1,3 +1,179 @@
1
+ # @owlmeans/server-auth-token
2
+
3
+ The server half of long-lived access tokens: a MongoDB token store, a guard that verifies a
4
+ presented token and turns it into the same `Auth` payload a browser session produces, the
5
+ list / create / revoke handlers, a shared issuer for other minting paths (an OAuth token endpoint),
6
+ and a coguard helper that admits a token on every already-guarded route. A backend uses it when API
7
+ clients, CLIs or coding agents should call the same routes a signed-in person does. The token
8
+ format, routes and record types live in `@owlmeans/auth-token`; the browser management panel is
9
+ `@owlmeans/web-auth-token`; issuing tokens through an OAuth grant is `@owlmeans/server-oauth`, which
10
+ calls this package's issuer.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ bun add @owlmeans/server-auth-token@^0.1.18
16
+ ```
17
+
18
+ ## Concepts
19
+
20
+ - **Access token** — `<prefix><base58 of 24 random bytes>`; the prefix defaults to `owl_`. The
21
+ plaintext is returned once at creation; the store keeps only its SHA-256 `hash` and a short
22
+ `display` form.
23
+ - **Guard, not authentication** — the guard verifies what arrives and resolves an `Auth` with
24
+ `type: AuthroizationType.AuthToken`; `authenticated()` always returns `null`, nothing is exchanged.
25
+ - **Prefix claim** — the guard matches only an `Authorization` value with the `AUTH-TOKEN` or
26
+ `Bearer` scheme that carries the deployment's prefix, so it coexists with other bearer guards.
27
+ - **Scope intersection** — on every request the token's scopes are intersected with its identity
28
+ profile's; a missing or expired profile refuses the token.
29
+ - **Audience** — a token minted through OAuth carries `audience`; a guard configured with
30
+ `resources` refuses a token whose audience does not intersect them. Without `resources`, every
31
+ token is admitted.
32
+ - **Deny list** — `denyAliases` names routes the guard never claims, so an interactive-only route
33
+ stays a 401 for a token even when the guard is inherited.
34
+
35
+ ## Usage
36
+
37
+ ### Register the store and the guard
38
+
39
+ ```typescript
40
+ import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token'
41
+ import { AUTH_IDENTITY_DB_ALIAS } from '@owlmeans/server-auth-identity'
42
+ import { appendAuthTokenGuard, appendAuthTokenResources } from '@owlmeans/server-auth-token'
43
+
44
+ appendAuthTokenResources(context, AUTH_IDENTITY_DB_ALIAS) // same dbAlias as the identity resources
45
+ appendAuthTokenGuard(context, GUARD_AUTH_TOKEN, {
46
+ prefix: 'vib_', // also written to cfg.authToken.prefix
47
+ denyAliases: [protocols.tokens.create.alias, protocols.tokens.revoke.alias, checkoutProtocol.alias],
48
+ })
49
+ ```
50
+
51
+ ### Bind the token routes
52
+
53
+ ```typescript
54
+ import { makeAuthTokenEntrypoints } from '@owlmeans/auth-token'
55
+ import { bind } from '@owlmeans/server-entrypoint'
56
+ import { createAccessToken, listAccessTokens, revokeAccessToken } from '@owlmeans/server-auth-token'
57
+
58
+ const tokens = makeAuthTokenEntrypoints({ parent: account.base })
59
+
60
+ context.registerEntrypoints([
61
+ bind(tokens.list, listAccessTokens(tokens.list)),
62
+ bind(tokens.create, createAccessToken(tokens.create)),
63
+ bind(tokens.revoke, revokeAccessToken(tokens.revoke)),
64
+ ])
65
+ ```
66
+
67
+ `revokeAccessToken(protocol, { allowAccessTokens: true })` lets a token revoke the same person's
68
+ tokens (for an agent-facing surface); ownership is still checked and minting stays refused.
69
+
70
+ ### Admit tokens on every guarded route
71
+
72
+ ```typescript
73
+ import { withAuthTokenCoguard } from '@owlmeans/server-auth-token'
74
+
75
+ export const guardedProtocols = withAuthTokenCoguard(appProtocols) // before creating bindings
76
+ ```
77
+
78
+ The coguard is appended after each protocol's existing guards; protocols without a guard are left
79
+ alone, and running it twice changes nothing.
80
+
81
+ ### Restrict a surface to tokens issued for it
82
+
83
+ ```typescript
84
+ appendAuthTokenGuard(context, 'guard:mcp-token', {
85
+ resources: ctx => [mcpResourceUri(ctx)], // app function, resolved per request
86
+ })
87
+ ```
88
+
89
+ ### Mint from another flow
90
+
91
+ ```typescript
92
+ import { accessTokenIssuerOf, refuseTokenAuth } from '@owlmeans/server-auth-token'
93
+
94
+ refuseTokenAuth(req, 'token-mint') // a token may never mint a token
95
+ const issued = await accessTokenIssuerOf(context).issueAccessToken(
96
+ { entityId, userId, profileId, role, scopes: ownScopes },
97
+ { name: 'MCP connector', scopes: ['*'], expiresIn: 3600, audience: [resourceUri] },
98
+ )
99
+ // issued.token is the plaintext, shown once; issued.record is the hash-free view
100
+ ```
101
+
102
+ ## API
103
+
104
+ ### Registration and guard
105
+
106
+ | Symbol | Purpose |
107
+ |---|---|
108
+ | `appendAuthTokenResources(ctx, dbAlias?)` | Registers `makeAccessTokenResource(dbAlias)` |
109
+ | `appendAuthTokenGuard(ctx, alias?, opts?)` | Registers the guard (default alias `GUARD_AUTH_TOKEN`); writes `opts.prefix` into `cfg.authToken.prefix` |
110
+ | `makeAuthTokenGuard(alias?, opts?)` | The `GuardService` |
111
+ | `makeAccessTokenResource(dbAlias?)` | Mongo resource at `AUTH_TOKEN_RESOURCE`, collection `access-token`; indexes `hash` (unique), `owner` (`entityId`, `profileId`), `expiresAt` (sparse) |
112
+ | `withAuthTokenCoguard(tree, guard?)` | Same-shaped protocol tree with the token guard appended to every guarded protocol |
113
+ | `prefixOf(context, opts?)` | Prefix from guard options, then `cfg.authToken.prefix`, then `owl_` |
114
+
115
+ ### Handlers and issuance
116
+
117
+ | Symbol | Purpose |
118
+ |---|---|
119
+ | `listAccessTokens(protocol)` | The caller's tokens in the caller's organization entity, newest first, without hashes |
120
+ | `createAccessToken(protocol)` | Mints a token from the session; refuses token auth; scopes may only narrow |
121
+ | `revokeAccessToken(protocol, opts?)` | Sets `revokedAt` on the caller's own token; idempotent; a foreign id answers like an unknown one |
122
+ | `accessTokenIssuerOf(ctx).issueAccessToken(subject, request)` | The shared minting path; `expiresIn` is clamped to `AUTH_TOKEN_MAX_TTL` |
123
+ | `makeAccessTokenIssuer(ctx)` | Builds an `AccessTokenIssuer` (unmemoized) |
124
+ | `refuseTokenAuth(req, what)` | Throws `AuthForbidden(what)` when `req.auth.type` is an access token |
125
+ | `tokenHashHelper.hashAccessToken(token)` | SHA-256 hex — the stored form |
126
+ | `tokenHashHelper.mintAccessToken(prefix)` | `MintedToken` `{ token, hash, display }` |
127
+ | `createTokenHashHelper()` | Builds a `TokenHashHelper` |
128
+ | `issueAccessToken(ctx, subject, request)`, `hashAccessToken(token)` | Deprecated wrappers |
129
+ | `SERVER_AUTH_TOKEN` | `'server-auth-token'` — module alias for error locations |
130
+
131
+ ### Types
132
+
133
+ | Symbol | Purpose |
134
+ |---|---|
135
+ | `AuthTokenGuardOptions` | `prefix?`, `denyAliases?`, `touchInterval?` (default 5 min), `resourceAlias?`, `profileAlias?`, `resources?` |
136
+ | `AuthTokenConfig` | `ServerConfig` with `authToken?: { prefix? }` |
137
+ | `AuthTokenContext` | `ServerContext<AuthTokenConfig>` |
138
+ | `AccessTokenResource` | `MongoResource<AccessTokenRecord>` |
139
+ | `IssueAccessTokenSubject` | `{ entityId, userId, profileId, role, scopes }` |
140
+ | `IssueAccessTokenRequest` | `CreateAccessToken` (`name`, `scopes?`, `expiresIn?`) plus `audience?` |
141
+ | `AccessTokenIssuer`, `RevokeAccessTokenOptions`, `MintedToken`, `TokenHashHelper` | Supporting types |
142
+
143
+ ## Guard behaviour
144
+
145
+ A presented token is refused when it is unknown, revoked, expired, outside the configured
146
+ `resources`, or when its identity profile is missing, unreadable or expired. On success the payload
147
+ carries the token's **display** form (never the secret), the profile's `role`, the intersected
148
+ scopes, and an `entitySlug` resolved through `ENTITY_RESOLVER` when one is registered. `lastUsedAt`
149
+ is written fire-and-forget at most once per `touchInterval`. Refusals are logged once a minute per
150
+ token and reason, with the record id only.
151
+
152
+ ## Common pitfalls
153
+
154
+ - Passing `prefix` only to a guard you build with `makeAuthTokenGuard` — the minting handler reads the
155
+ prefix from config, so the two disagree and every new token is a 401. Use `appendAuthTokenGuard`.
156
+ - Registering the token store on a different `dbAlias` than the identity resources.
157
+ - Forgetting the deny list — a coguard-admitted token then reaches routes that must stay
158
+ session-only (minting, checkout, starting an OAuth flow). A child route cannot drop an inherited
159
+ guard; the refusal belongs in `denyAliases`.
160
+ - Expecting a requested scope the caller lacks to be dropped — it is refused with
161
+ `AuthForbidden('scope')`.
162
+ - Treating `lastUsedAt` as an access log — it is throttled and best-effort.
163
+ - Decorating protocols with `withAuthTokenCoguard` after bindings were created.
164
+
165
+ The `server-auth-token` skill covers the guard, the store and the deny-list rule in depth; the
166
+ `auth-token` skill covers the format and routes.
167
+
168
+ ## Related packages
169
+
170
+ - [`@owlmeans/auth-token`](../auth-token) — token format, routes, record types, constants
171
+ - [`@owlmeans/web-auth-token`](../web-auth-token) — the browser token management panel
172
+ - [`@owlmeans/server-oauth`](../server-oauth) — OAuth authorization server that mints audience-scoped tokens
173
+ - [`@owlmeans/server-auth-identity`](../server-auth-identity) — the identity profiles a token is bound to
174
+ - [`@owlmeans/mongo-resource`](../mongo-resource) — the token store's backend
175
+ - [`@owlmeans/server-api`](../server-api) — the `handlers()` builder the handlers use
176
+
1
177
  <!-- owlmeans:agent-guidance:start -->
2
178
  ## Agent guidance
3
179
 
@@ -6,7 +182,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
6
182
  your project's skill store (`.agents/skills/`):
7
183
 
8
184
  ```sh
9
- npx @owlmeans/agent-skills@^0.1.18-rc.20
185
+ npx @owlmeans/agent-skills@^0.1.18
10
186
  ```
11
187
 
12
188
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
- "schemaVersion": 2,
2
+ "schemaVersion": 3,
3
3
  "package": "@owlmeans/server-auth-token",
4
- "version": "0.1.18-rc.8",
5
- "generatedAt": "2026-09-12T14:18:54.799Z",
4
+ "version": "0.1.18",
5
+ "generatedAt": "2026-10-28T00:31:34.770Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: server-auth-token
3
- description: How to use @owlmeans/server-auth-token — the server half of long-lived access tokens — the Mongo store, the guard that verifies a presented token and intersects its scopes with the profile's, the mint/list/revoke handlers, and the coguard that admits a token on every already-guarded route. Auto-invoked when registering the token guard or resources, mounting the token handlers, or diagnosing a 401 on a route an access token should reach.
3
+ description: How to use @owlmeans/server-auth-token — the server half of long-lived access tokens — the Mongo store, the guard that verifies a presented token and intersects its scopes with the profile's, the mint/list/revoke handlers, the shared `accessTokenIssuerOf(ctx).issueAccessToken`, audience admission for OAuth-issued tokens, and the coguard that admits a token on every already-guarded route. Auto-invoked when registering the token guard or resources, mounting the token handlers, or diagnosing a 401 on a route an access token should reach.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/server-auth-token
9
9
 
10
10
  **Layer:** Server
11
- **Install:** `"@owlmeans/server-auth-token": "^0.1.18-rc.8"` in `dependencies`
11
+ **Install:** `"@owlmeans/server-auth-token": "^0.1.18"` in `dependencies`
12
12
  **Contracts:** `@owlmeans/auth-token` — the record, the routes, the format helpers
13
13
 
14
14
  ## Key Exports
@@ -20,10 +20,12 @@ user-invocable: false
20
20
  | `makeAuthTokenGuard(alias?, opts?)` | The guard itself |
21
21
  | `makeAccessTokenResource(dbAlias?)` | The Mongo resource, with its three indexes |
22
22
  | `prefixOf(context, opts?)` | The deployment's prefix: guard options → config → default |
23
- | `hashAccessToken(token)` · `mintAccessToken(prefix)` | The stored form; one minted `{ token, hash, display }` |
23
+ | `tokenHashHelper` — `.hashAccessToken(token)` · `.mintAccessToken(prefix)` | The stored form; one minted `{ token, hash, display }` |
24
24
  | `withAuthTokenCoguard(protocolTree, guard?)` | Return the same-shaped immutable tree with the guard appended to every already-guarded protocol |
25
- | `listAccessTokens` · `createAccessToken` · `revokeAccessToken` | The three handlers |
26
- | `AuthTokenGuardOptions` (`prefix`, `denyAliases`, `touchInterval`, `resourceAlias`, `profileAlias`) · `AuthTokenConfig` · `AccessTokenResource` | Types |
25
+ | `listAccessTokens(protocol)` · `createAccessToken(protocol)` · `revokeAccessToken(protocol, { allowAccessTokens? })` | The three handlers; only revoke takes an option (`RevokeAccessTokenOptions`) |
26
+ | `accessTokenIssuerOf(ctx).issueAccessToken(subject, request)` | Mint one token for `{ entityId, userId, profileId, role, scopes }` — what `createAccessToken` does over an HTTP body, and what an OAuth token endpoint calls over a session it verified itself. `request` is `CreateAccessToken` plus `audience?: string[]` |
27
+ | `refuseTokenAuth(req, what)` | The one "interactive session only" check — throws `AuthForbidden` when `req.auth.type` is an access token |
28
+ | `AuthTokenGuardOptions` (`prefix`, `denyAliases`, `touchInterval`, `resourceAlias`, `profileAlias`, `resources`) · `IssueAccessTokenSubject` · `IssueAccessTokenRequest` · `RevokeAccessTokenOptions` · `AuthTokenConfig` · `AccessTokenResource` | Types |
27
29
 
28
30
  ## Wiring
29
31
 
@@ -77,19 +79,39 @@ Three properties keep it from colliding with the guards beside it:
77
79
  - `entitySlug` is resolved through `ENTITY_RESOLVER` when one is registered, so the payload is
78
80
  identical to a browser session's rather than carrying a raw id.
79
81
 
82
+ **Audience admission is opt-in.** A token minted through an OAuth grant carries `audience` (the resources
83
+ it is FOR, RFC 8707). A guard configured with `resources` (`string[]` or `(ctx) => string[]`, resolved
84
+ per request, because `appendAuthTokenGuard` runs from `makeContext` before a secret-mounted hostname is
85
+ necessarily readable) refuses — as an ordinary non-match, a 401 — a token whose non-empty `audience`
86
+ does not intersect it. A token with **no** audience (every hand-minted one) is admitted everywhere its
87
+ scopes reach, and a guard with no `resources` admits every token whatever its audience, so a deployment
88
+ that never mints an audience-restricted token sees no change. Two guards over different surfaces are
89
+ how a token bound to `/mcp` stays out of the ordinary REST API while a REST-scoped token still works
90
+ through `/mcp`.
91
+
80
92
  `lastUsedAt` is a **throttled, fire-and-forget** write (`touchInterval`, default 5 minutes). A usage
81
93
  timestamp is never a reason to fail a request, and awaiting it would put a database write on the
82
94
  critical path of every authenticated call. It answers one question — "is this token still in use?" —
83
95
  and is not an access log.
84
96
 
85
- ## A token may never mint or revoke a token
97
+ ## A token may never mint a token; it revokes one only where the deployment opts in
86
98
 
87
99
  Minting is the one operation that turns a stolen credential into a permanent one: a token that can
88
- create tokens survives the revocation of the token that leaked. `createAccessToken` and
89
- `revokeAccessToken` refuse a request whose `auth.type` is `AuthroizationType.AuthToken`, and a
100
+ create tokens survives the revocation of the token that leaked. `createAccessToken` and any other
101
+ minting path (an OAuth consent approval calls `refuseTokenAuth` before it snapshots the subject)
102
+ refuse a request whose `auth.type` is `AuthroizationType.AuthToken` — always, with no option — and a
90
103
  deployment additionally names those routes in the guard's **deny list**, so the refusal is a 401 at
91
104
  the boundary rather than a check every future handler has to remember.
92
105
 
106
+ `revokeAccessToken(protocol)` refuses a token the same way by default. `revokeAccessToken(protocol,
107
+ { allowAccessTokens: true })` admits one — for a deployment's coding-agent surface that lets a person
108
+ clean up their own tokens (Viable's connector binds it on `connect.account.tokens.revoke`, while the
109
+ browser's own `/tokens/:id` route stays session-only and on the deny list). The option widens the
110
+ CREDENTIAL only: the token revoked must still be the caller's own profile in its own organization
111
+ (`makeEntityScope(req).requireEntityKey()`), a foreign or unknown id still answers `AuthForbidden`
112
+ alike, and a token may revoke itself. Revoking never creates a credential, so it cannot make a
113
+ stolen token permanent; at worst it signs the person's other agents out.
114
+
93
115
  Minting only ever narrows: asking for a scope the caller does not hold is **refused**, not silently
94
116
  dropped — a token that quietly grants less than it was asked for fails later, somewhere else, with
95
117
  an error about the wrong thing. Revoke is idempotent (a retry looks like a second revoke), and
@@ -121,7 +143,7 @@ works.
121
143
  ## Tests
122
144
 
123
145
  `bun test ./tests` in the package — what the guard claims, what it resolves (including that a token
124
- can never outrank its profile), the mint/list/revoke rules, and the coguard's four properties.
146
+ can never outrank its profile), the mint/list/revoke rules (the revoke option: own profile and organization only, minting still refused), `accessTokenIssuerOf(ctx).issueAccessToken` parity with the route, audience admission, and the coguard's four properties.
125
147
 
126
148
  ## Depends On
127
149
 
@@ -132,5 +154,6 @@ can never outrank its profile), the mint/list/revoke rules, and the coguard's fo
132
154
 
133
155
  ## Related
134
156
 
135
- - [[auth-token]] — the format, the routes and the client carrier guard
157
+ - [[auth-token]] — the format, the routes, `audience` and the client carrier guard
158
+ - [[server-oauth]] — the authorization server that mints audience-scoped tokens through `accessTokenIssuerOf(ctx).issueAccessToken`
136
159
  - [[web-auth-token]] — the management panel · [[auth-protocol]] · [[server-auth]]
package/build/guard.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import type { GuardService } from '@owlmeans/entrypoint';
2
- import type { AuthTokenContext, AuthTokenGuardOptions } from './types.js';
3
- /** Where the deployment's prefix comes from: the guard's own options, then config, then default. */
4
- export declare const prefixOf: (context: AuthTokenContext, opts?: AuthTokenGuardOptions) => string;
2
+ import type { AuthTokenGuardOptions } from './types.js';
5
3
  /**
6
4
  * The guard that verifies a long-lived access token.
7
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAqC,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAI3F,OAAO,KAAK,EAAwC,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAE/G,oGAAoG;AACpG,eAAO,MAAM,QAAQ,YAAa,gBAAgB,SAAS,qBAAqB,KAAG,MACc,CAAA;AAEjG;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,WACtB,MAAM,SAA2B,qBAAqB,KAC5D,YAsGF,CAAA"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAqC,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAK3F,OAAO,KAAK,EAA0D,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAK/G;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,WACtB,MAAM,SAA2B,qBAAqB,KAC5D,YA6HF,CAAA"}
package/build/guard.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { ALL_SCOPES, AuthroizationType } from '@owlmeans/auth';
2
- import { AUTH_TOKEN_DEFAULT_PREFIX, AUTH_TOKEN_SCHEME, AUTH_TOKEN_RESOURCE, AUTH_TOKEN_TOUCH_INTERVAL, BEARER_SCHEME, GUARD_AUTH_TOKEN, isAccessToken, parseAuthorizationHeader } from '@owlmeans/auth-token';
2
+ import { AUTH_TOKEN_SCHEME, AUTH_TOKEN_RESOURCE, AUTH_TOKEN_TOUCH_INTERVAL, BEARER_SCHEME, GUARD_AUTH_TOKEN, tokenFormatHelper } from '@owlmeans/auth-token';
3
3
  import { AUTH_HEADER } from '@owlmeans/auth';
4
4
  import { ENTITY_RESOLVER } from '@owlmeans/auth-common';
5
5
  import { createService } from '@owlmeans/context';
6
6
  import { AUTH_IDENTITY_PROFILE } from '@owlmeans/server-auth-identity';
7
- import { hashAccessToken } from './hash.js';
8
- /** Where the deployment's prefix comes from: the guard's own options, then config, then default. */
9
- export const prefixOf = (context, opts) => opts?.prefix ?? context.cfg.authToken?.prefix ?? AUTH_TOKEN_DEFAULT_PREFIX;
7
+ import { tokenHashHelper } from './hash.js';
8
+ import { prefixOf } from './prefix.js';
9
+ import { logger, logThrottle } from '@owlmeans/log';
10
+ const log = logger('server-auth-token');
10
11
  /**
11
12
  * The guard that verifies a long-lived access token.
12
13
  *
@@ -26,14 +27,26 @@ export const prefixOf = (context, opts) => opts?.prefix ?? context.cfg.authToken
26
27
  * outlive or outrank the person who minted it.
27
28
  */
28
29
  export const makeAuthTokenGuard = (alias = GUARD_AUTH_TOKEN, opts = {}) => {
30
+ /**
31
+ * A presented access token the guard did not accept. Never the token, not even its display form:
32
+ * its record id only. Once a minute per token and reason — a client retrying a revoked token calls every second.
33
+ */
34
+ const refuse = (reason, record) => {
35
+ if (logThrottle(`auth-token:${reason}:${record?.id ?? ''}`, 60_000)) {
36
+ log.warn('Access token refused', {
37
+ reason, tokenId: record?.id, entityId: record?.entityId,
38
+ }, { event: 'auth.refused' });
39
+ }
40
+ return false;
41
+ };
29
42
  const touchInterval = opts.touchInterval ?? AUTH_TOKEN_TOUCH_INTERVAL;
30
43
  const present = (req, prefix) => {
31
- const parsed = parseAuthorizationHeader(req.headers?.[AUTH_HEADER]);
44
+ const parsed = tokenFormatHelper.parseAuthorizationHeader(req.headers?.[AUTH_HEADER]);
32
45
  if (parsed == null)
33
46
  return null;
34
47
  if (parsed.scheme !== AUTH_TOKEN_SCHEME && parsed.scheme !== BEARER_SCHEME)
35
48
  return null;
36
- return isAccessToken(parsed.value, prefix) ? parsed.value : null;
49
+ return tokenFormatHelper.isAccessToken(parsed.value, prefix) ? parsed.value : null;
37
50
  };
38
51
  const service = createService(alias, {
39
52
  match: async (req) => {
@@ -56,13 +69,23 @@ export const makeAuthTokenGuard = (alias = GUARD_AUTH_TOKEN, opts = {}) => {
56
69
  if (presented == null)
57
70
  return false;
58
71
  const tokens = context.resource(opts.resourceAlias ?? AUTH_TOKEN_RESOURCE);
59
- const record = await tokens.load({ hash: hashAccessToken(presented) });
72
+ const record = await tokens.load({ hash: tokenHashHelper.hashAccessToken(presented) });
60
73
  if (record == null)
61
- return false;
74
+ return refuse('unknown');
62
75
  if (record.revokedAt != null)
63
- return false;
76
+ return refuse('revoked', record);
64
77
  if (record.expiresAt != null && new Date(record.expiresAt) < new Date())
65
- return false;
78
+ return refuse('expired', record);
79
+ // A token minted through an OAuth grant carries the resource(s) it was issued FOR. A token
80
+ // with no audience is the ordinary hand-minted kind and is admitted everywhere its scopes
81
+ // reach, exactly as before this check existed — the guard has to OPT IN with `resources` to
82
+ // narrow anything, so a deployment that never touches this option sees no change at all.
83
+ const resources = typeof opts.resources === 'function' ? opts.resources(context) : opts.resources;
84
+ if (record.audience != null && record.audience.length > 0
85
+ && resources != null && resources.length > 0
86
+ && !record.audience.some(resource => resources.includes(resource))) {
87
+ return refuse('audience', record);
88
+ }
66
89
  // A token is only ever as good as the profile behind it. Reading the profile per request is
67
90
  // what makes revoking a person's access revoke every token they ever minted, without any
68
91
  // token record being touched.
@@ -72,12 +95,12 @@ export const makeAuthTokenGuard = (alias = GUARD_AUTH_TOKEN, opts = {}) => {
72
95
  profile = await profiles.load({ entityId: record.entityId, profileId: record.profileId });
73
96
  }
74
97
  catch {
75
- return false;
98
+ return refuse('profile-unreadable', record);
76
99
  }
77
100
  if (profile == null)
78
- return false;
101
+ return refuse('profile', record);
79
102
  if (profile.expiresAt != null && new Date(profile.expiresAt) < new Date())
80
- return false;
103
+ return refuse('profile-expired', record);
81
104
  const profileScopes = profile.scopes ?? [];
82
105
  const scopes = profileScopes.includes(ALL_SCOPES)
83
106
  ? record.scopes
@@ -114,7 +137,7 @@ export const makeAuthTokenGuard = (alias = GUARD_AUTH_TOKEN, opts = {}) => {
114
137
  // Fire and forget: a usage timestamp is never a reason to fail a request, and awaiting it
115
138
  // would put a database write on the critical path of every authenticated call.
116
139
  void tokens.save({ ...record, lastUsedAt: new Date() })
117
- .catch((e) => console.error('auth-token: lastUsedAt', e));
140
+ .catch((e) => { log.warn('Access token lastUsedAt not saved', { tokenId: record.id, error: e }); });
118
141
  }
119
142
  return true;
120
143
  },
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EACL,yBAAyB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,yBAAyB,EAC5F,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,wBAAwB,EACzE,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAG3C,oGAAoG;AACpG,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAyB,EAAE,IAA4B,EAAU,EAAE,CAC1F,IAAI,EAAE,MAAM,IAAK,OAAO,CAAC,GAAuB,CAAC,SAAS,EAAE,MAAM,IAAI,yBAAyB,CAAA;AAEjG;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAK,GAAW,gBAAgB,EAAE,IAAI,GAA0B,EAAE,EACpD,EAAE;IAChB,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,yBAAyB,CAAA;IAErE,MAAM,OAAO,GAAG,CAAC,GAA6B,EAAE,MAAc,EAAiB,EAAE;QAC/E,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;QACnE,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;QAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,iBAAiB,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa;YAAE,OAAO,IAAI,CAAA;QAEvF,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAClE,CAAC,CAAA;IAED,MAAM,OAAO,GAAiB,aAAa,CAAe,KAAK,EAAE;QAC/D,KAAK,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACjB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAqC,CAAA;YACtE,IAAI,GAAG,IAAI,IAAI;gBAAE,OAAO,KAAK,CAAA;YAC7B,wFAAwF;YACxF,0FAA0F;YAC1F,2FAA2F;YAC3F,uEAAuE;YACvE,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1F,OAAO,KAAK,CAAA;YACd,CAAC;YAED,OAAO,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAA;QACtD,CAAC;QAED,MAAM,EAAE,KAAK,EAAK,GAAoB,EAAE,GAA2B,EAAE,EAAE;YACrE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAqC,CAAA;YACtE,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;YACtC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACtC,IAAI,SAAS,IAAI,IAAI;gBAAE,OAAO,KAAU,CAAA;YAExC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAsB,IAAI,CAAC,aAAa,IAAI,mBAAmB,CAAC,CAAA;YAC/F,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACtE,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,KAAU,CAAA;YACrC,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI;gBAAE,OAAO,KAAU,CAAA;YAC/C,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE;gBAAE,OAAO,KAAU,CAAA;YAE1F,4FAA4F;YAC5F,yFAAyF;YACzF,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAC/B,IAAI,CAAC,YAAY,IAAI,qBAAqB,CAC3C,CAAA;YACD,IAAI,OAAO,GAA2B,IAAI,CAAA;YAC1C,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;YAC3F,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAU,CAAA;YACnB,CAAC;YACD,IAAI,OAAO,IAAI,IAAI;gBAAE,OAAO,KAAU,CAAA;YACtC,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE;gBAAE,OAAO,KAAU,CAAA;YAE5F,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;YAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC/C,CAAC,CAAC,MAAM,CAAC,MAAM;gBACf,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;oBAClC,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;YAElE,0FAA0F;YAC1F,2FAA2F;YAC3F,4BAA4B;YAC5B,IAAI,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAA;YAChC,IAAI,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAwB,eAAe,CAAC,CAAA;gBACxE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACnD,IAAI,MAAM,IAAI,IAAI;oBAAE,UAAU,GAAG,MAAM,CAAC,IAAI,CAAA;YAC9C,CAAC;YAED,GAAG,CAAC,OAAO,CAAC;gBACV,uFAAuF;gBACvF,0CAA0C;gBAC1C,KAAK,EAAE,MAAM,CAAC,OAAO;gBACrB,IAAI,EAAE,iBAAiB,CAAC,SAAS;gBACjC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,UAAU;gBACV,MAAM;gBACN,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;gBAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;gBACrC,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvE,CAAC,CAAA;YAEV,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAA;YAClF,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,aAAa,EAAE,CAAC;gBACtC,0FAA0F;gBAC1F,+EAA+E;gBAC/E,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;qBACpD,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,CAAA;YACtE,CAAC;YAED,OAAO,IAAS,CAAA;QAClB,CAAC;QAED,mFAAmF;QACnF,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI;KAChC,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EACL,iBAAiB,EAAE,mBAAmB,EAAE,yBAAyB,EACjE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EACnD,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAEtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEnD,MAAM,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAA;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAK,GAAW,gBAAgB,EAAE,IAAI,GAA0B,EAAE,EACpD,EAAE;IAChB;;;OAGG;IACH,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,MAA2C,EAAS,EAAE;QACpF,IAAI,WAAW,CAAC,cAAc,MAAM,IAAI,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBAC/B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ;aACxD,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAA;QAC/B,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,yBAAyB,CAAA;IAErE,MAAM,OAAO,GAAG,CAAC,GAA6B,EAAE,MAAc,EAAiB,EAAE;QAC/E,MAAM,MAAM,GAAG,iBAAiB,CAAC,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;QACrF,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;QAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,iBAAiB,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa;YAAE,OAAO,IAAI,CAAA;QAEvF,OAAO,iBAAiB,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IACpF,CAAC,CAAA;IAED,MAAM,OAAO,GAAiB,aAAa,CAAe,KAAK,EAAE;QAC/D,KAAK,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACjB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAqC,CAAA;YACtE,IAAI,GAAG,IAAI,IAAI;gBAAE,OAAO,KAAK,CAAA;YAC7B,wFAAwF;YACxF,0FAA0F;YAC1F,2FAA2F;YAC3F,uEAAuE;YACvE,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1F,OAAO,KAAK,CAAA;YACd,CAAC;YAED,OAAO,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAA;QACtD,CAAC;QAED,MAAM,EAAE,KAAK,EAAK,GAAoB,EAAE,GAA2B,EAAE,EAAE;YACrE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAqC,CAAA;YACtE,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;YACtC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACtC,IAAI,SAAS,IAAI,IAAI;gBAAE,OAAO,KAAU,CAAA;YAExC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAsB,IAAI,CAAC,aAAa,IAAI,mBAAmB,CAAC,CAAA;YAC/F,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACtF,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAC,SAAS,CAAM,CAAA;YACjD,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAC,SAAS,EAAE,MAAM,CAAM,CAAA;YACnE,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE;gBAAE,OAAO,MAAM,CAAC,SAAS,EAAE,MAAM,CAAM,CAAA;YAC9G,2FAA2F;YAC3F,0FAA0F;YAC1F,4FAA4F;YAC5F,yFAAyF;YACzF,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAA;YACjG,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;mBACpD,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;mBACzC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBACrE,OAAO,MAAM,CAAC,UAAU,EAAE,MAAM,CAAM,CAAA;YACxC,CAAC;YAED,4FAA4F;YAC5F,yFAAyF;YACzF,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAC/B,IAAI,CAAC,YAAY,IAAI,qBAAqB,CAC3C,CAAA;YACD,IAAI,OAAO,GAA2B,IAAI,CAAA;YAC1C,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;YAC3F,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAM,CAAA;YAClD,CAAC;YACD,IAAI,OAAO,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAC,SAAS,EAAE,MAAM,CAAM,CAAA;YAC1D,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE;gBAAE,OAAO,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAM,CAAA;YAExH,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;YAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC/C,CAAC,CAAC,MAAM,CAAC,MAAM;gBACf,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;oBAClC,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;YAElE,0FAA0F;YAC1F,2FAA2F;YAC3F,4BAA4B;YAC5B,IAAI,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAA;YAChC,IAAI,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAwB,eAAe,CAAC,CAAA;gBACxE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACnD,IAAI,MAAM,IAAI,IAAI;oBAAE,UAAU,GAAG,MAAM,CAAC,IAAI,CAAA;YAC9C,CAAC;YAED,GAAG,CAAC,OAAO,CAAC;gBACV,uFAAuF;gBACvF,0CAA0C;gBAC1C,KAAK,EAAE,MAAM,CAAC,OAAO;gBACrB,IAAI,EAAE,iBAAiB,CAAC,SAAS;gBACjC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,UAAU;gBACV,MAAM;gBACN,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;gBAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;gBACrC,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvE,CAAC,CAAA;YAEV,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAA;YAClF,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,aAAa,EAAE,CAAC;gBACtC,0FAA0F;gBAC1F,+EAA+E;gBAC/E,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;qBACpD,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;YAC/G,CAAC;YAED,OAAO,IAAS,CAAA;QAClB,CAAC;QAED,mFAAmF;QACnF,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI;KAChC,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { AuthTokenEntrypoints } from '@owlmeans/auth-token';
2
+ export declare const createAccessToken: (protocol: AuthTokenEntrypoints['create']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<{
3
+ body: import("@owlmeans/auth-token").CreateAccessToken;
4
+ }, import("@owlmeans/auth-token").IssuedAccessToken>>;
5
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/handlers/create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAOhE,eAAO,MAAM,iBAAiB,aAAc,oBAAoB,CAAC,QAAQ,CAAC;;qDAYxE,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { AuthForbidden, AuthRole } from '@owlmeans/auth';
2
+ import { makeEntityScope } from '@owlmeans/auth-common';
3
+ import { handlers } from '@owlmeans/server-api';
4
+ import { accessTokenIssuerOf } from './issue.js';
5
+ import { refuseTokenAuth } from './refuse.js';
6
+ export const createAccessToken = (protocol) => handlers().body(protocol, async (payload, context, req) => {
7
+ const ctx = context;
8
+ refuseTokenAuth(req, 'token-mint');
9
+ const entityId = makeEntityScope(req).requireEntityKey();
10
+ const profileId = req.auth?.profileId;
11
+ const userId = req.auth?.userId;
12
+ if (profileId == null || userId == null)
13
+ throw new AuthForbidden('profile');
14
+ return accessTokenIssuerOf(ctx).issueAccessToken({
15
+ entityId, profileId, userId, role: req.auth?.role ?? AuthRole.User, scopes: req.auth?.scopes ?? [],
16
+ }, payload);
17
+ });
18
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/handlers/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAwC,EAAE,EAAE,CAAC,QAAQ,EAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;IACzJ,MAAM,GAAG,GAAG,OAA2B,CAAA;IACvC,eAAe,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;IAElC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAA;IACxD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,CAAA;IACrC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,CAAA;IAC/B,IAAI,SAAS,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI;QAAE,MAAM,IAAI,aAAa,CAAC,SAAS,CAAC,CAAA;IAE3E,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC;QAC/C,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE;KACnG,EAAE,OAAO,CAAC,CAAA;AACb,CAAC,CAAC,CAAA"}
@@ -1,12 +1,12 @@
1
- import type { AccessTokenList, IssuedAccessToken } from '@owlmeans/auth-token';
2
- import type { AuthTokenEntrypoints } from '@owlmeans/auth-token';
3
- export declare const listAccessTokens: (protocol: AuthTokenEntrypoints['list']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<import("@owlmeans/entrypoint").OpenRequest, AccessTokenList>>;
4
- export declare const createAccessToken: (protocol: AuthTokenEntrypoints['create']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<{
5
- body: import("@owlmeans/auth-token").CreateAccessToken;
6
- }, IssuedAccessToken>>;
7
- export declare const revokeAccessToken: (protocol: AuthTokenEntrypoints['revoke']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<{
8
- params: import("@owlmeans/auth-token").AccessTokenParams;
9
- }, {
10
- id: string;
11
- }>>;
1
+ import type { IssuedAccessToken } from '@owlmeans/auth-token';
2
+ import type { AuthTokenContext } from '../types.js';
3
+ import type { IssueAccessTokenRequest, IssueAccessTokenSubject } from './types.js';
4
+ export * from './refuse.js';
5
+ export * from './issue.js';
6
+ export * from './list.js';
7
+ export * from './create.js';
8
+ export * from './revoke.js';
9
+ export type { IssueAccessTokenRequest, IssueAccessTokenSubject, RevokeAccessTokenOptions } from './types.js';
10
+ /** @deprecated compat:factory-refactor — use `accessTokenIssuerOf(ctx).issueAccessToken(…)` */
11
+ export declare const issueAccessToken: (ctx: AuthTokenContext, subject: IssueAccessTokenSubject, payload: IssueAccessTokenRequest) => Promise<IssuedAccessToken>;
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAAsC,iBAAiB,EACvE,MAAM,sBAAsB,CAAA;AAM7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AA0BhE,eAAO,MAAM,gBAAgB,aAAc,oBAAoB,CAAC,MAAM,CAAC,iLAarE,CAAA;AAEF,eAAO,MAAM,iBAAiB,aAAc,oBAAoB,CAAC,QAAQ,CAAC;;sBAsCxE,CAAA;AAEF,eAAO,MAAM,iBAAiB,aAAc,oBAAoB,CAAC,QAAQ,CAAC;;;;GAqBxE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAElF,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAE3B,YAAY,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE5G,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB,QACtB,gBAAgB,WAAW,uBAAuB,WAAW,uBAAuB,KACxF,OAAO,CAAC,iBAAiB,CAAsE,CAAA"}
@@ -1,94 +1,9 @@
1
- import { AuthForbidden, AuthroizationType, ALL_SCOPES, AuthRole } from '@owlmeans/auth';
2
- import { AUTH_TOKEN_MAX_TTL, AUTH_TOKEN_RESOURCE } from '@owlmeans/auth-token';
3
- import { requireEntityKey } from '@owlmeans/auth-common';
4
- import { handlers } from '@owlmeans/server-api';
5
- import { mintAccessToken } from '../hash.js';
6
- import { prefixOf } from '../guard.js';
7
- const view = (record) => {
8
- const { hash, ...rest } = record;
9
- return rest;
10
- };
11
- const tokens = (ctx) => ctx.resource(AUTH_TOKEN_RESOURCE);
12
- /**
13
- * A token may never mint another token.
14
- *
15
- * Minting is the one operation that turns a stolen credential into a permanent one: a token that
16
- * can create tokens survives the revocation of the token that leaked. Creating and revoking
17
- * therefore require a credential a person produced in a browser — which is also why the deployment
18
- * names these routes in the guard's deny list, so the refusal is a 401 at the boundary rather than
19
- * a check every future handler has to remember.
20
- */
21
- const refuseTokenAuth = (req, what) => {
22
- if (req.auth?.type === AuthroizationType.AuthToken) {
23
- throw new AuthForbidden(what);
24
- }
25
- };
26
- export const listAccessTokens = (protocol) => handlers().request(protocol, async (req, context) => {
27
- const ctx = context;
28
- const entityId = requireEntityKey(req);
29
- const profileId = req.auth?.profileId;
30
- if (profileId == null)
31
- throw new AuthForbidden('profile');
32
- const result = await tokens(ctx).list({ entityId, profileId }, { size: 0 });
33
- return {
34
- items: result.items
35
- .map(view)
36
- .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()),
37
- };
38
- });
39
- export const createAccessToken = (protocol) => handlers().body(protocol, async (payload, context, req) => {
40
- const ctx = context;
41
- refuseTokenAuth(req, 'token-mint');
42
- const entityId = requireEntityKey(req);
43
- const profileId = req.auth?.profileId;
44
- const userId = req.auth?.userId;
45
- if (profileId == null || userId == null)
46
- throw new AuthForbidden('profile');
47
- const own = req.auth?.scopes ?? [];
48
- const scopes = payload.scopes ?? own;
49
- // A token is a delegation, so it can only ever narrow. Asking for a scope the caller does not
50
- // hold is refused rather than silently dropped: a token that quietly grants less than it was
51
- // asked for fails later, somewhere else, with an error about the wrong thing.
52
- if (!own.includes(ALL_SCOPES) && scopes.some(scope => !own.includes(scope))) {
53
- throw new AuthForbidden('scope');
54
- }
55
- // The SAME resolver the guard uses, so a minted token is one this deployment's guard claims.
56
- const minted = mintAccessToken(prefixOf(ctx));
57
- const now = new Date();
58
- const record = await tokens(ctx).create({
59
- hash: minted.hash,
60
- display: minted.display,
61
- name: payload.name,
62
- userId,
63
- profileId,
64
- entityId,
65
- scopes,
66
- role: req.auth?.role ?? AuthRole.User,
67
- createdAt: now,
68
- ...(payload.expiresIn != null
69
- ? { expiresAt: new Date(now.getTime() + Math.min(payload.expiresIn * 1000, AUTH_TOKEN_MAX_TTL)) }
70
- : {}),
71
- });
72
- // The only moment the plaintext exists outside the caller's own machine.
73
- return { token: minted.token, record: view(record) };
74
- });
75
- export const revokeAccessToken = (protocol) => handlers().params(protocol, async (payload, context, req) => {
76
- const ctx = context;
77
- refuseTokenAuth(req, 'token-revoke');
78
- const entityId = requireEntityKey(req);
79
- const profileId = req.auth?.profileId;
80
- if (profileId == null)
81
- throw new AuthForbidden('profile');
82
- const record = await tokens(ctx).load(payload.id);
83
- // A token of another profile answers exactly as an unknown id does — an owner learns nothing
84
- // about tokens that are not theirs, not even that one exists.
85
- if (record == null || record.entityId !== entityId || record.profileId !== profileId) {
86
- throw new AuthForbidden('token');
87
- }
88
- // Idempotent: revoking twice is what a retry looks like.
89
- if (record.revokedAt == null) {
90
- await tokens(ctx).save({ ...record, revokedAt: new Date(), updatedAt: new Date() });
91
- }
92
- return { id: payload.id };
93
- });
1
+ import { accessTokenIssuerOf } from './issue.js';
2
+ export * from './refuse.js';
3
+ export * from './issue.js';
4
+ export * from './list.js';
5
+ export * from './create.js';
6
+ export * from './revoke.js';
7
+ /** @deprecated compat:factory-refactor — use `accessTokenIssuerOf(ctx).issueAccessToken(…)` */
8
+ export const issueAccessToken = async (ctx, subject, payload) => await accessTokenIssuerOf(ctx).issueAccessToken(subject, payload);
94
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGhD,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAI3B,+FAA+F;AAC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,GAAqB,EAAE,OAAgC,EAAE,OAAgC,EAC7D,EAAE,CAAC,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA"}