@boopkit/cap-users 0.7.0 → 0.8.0

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 CHANGED
@@ -132,6 +132,20 @@ router.get('/integrations', requireApiKey(), api.integrations); // an API key, n
132
132
 
133
133
  `requireApiKey` accepts the request only when `resolveBearer` resolved it from a key (`req.authStrategy === 'api-key'`), then runs the same `isAuthorized` grant check `requireAuth` does — so an expired per-key grant is refused here even though the key still resolves.
134
134
 
135
+ **A bearer door of your own.** `resolveBearer` is the API-key instantiation of an exported factory, `createBearerMiddleware(deps, { resolve, strategy, challenge })`. A capability that issues its own kind of token — OAuth access tokens, say — supplies its own `resolve` callback and gets cap-users' bearer handling unchanged: the same header parsing, the same refusal semantics (401 with your challenge, never a fall-through to the session cookie), the same `req.user`/`req.sessionToken` fields downstream code already reads.
136
+
137
+ ```ts
138
+ import { createBearerMiddleware } from '@boopkit/cap-users';
139
+
140
+ const resolveOauth = createBearerMiddleware(deps, {
141
+ resolve: (token) => tokenService.resolve(token), // null if it does not resolve
142
+ strategy: 'oauth', // written to req.authStrategy
143
+ challenge: 'Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"',
144
+ });
145
+ ```
146
+
147
+ Give your path its **own** `strategy` label. `requireApiKey` gates on the `'api-key'` literal specifically, so reusing that label would walk your token through the one gate whose purpose is to demand an independently revocable API key. `req.authStrategy` is typed `string` for exactly this reason, while the gate's comparison stays on the literal.
148
+
135
149
  Issue keys with `authService.createApiKey(userId)`, which returns the raw key once. Only `hashToken(apiKey)` is stored in `user_identities`, the same treatment a session cookie gets, so a read of that table hands nobody a working credential. Keys issued before this change were stored raw and will not resolve after it; reissue them.
136
150
 
137
151
  There is deliberately no route, screen, or command for minting a key. Handing out a credential that acts as a user is not a generic operation — who may do it, for whom, whether it needs a second factor or an approval, and what the audit trail looks like are answers only your application has, and a default affordance would answer them for you on the sensitive side. Wire `createApiKey` behind whatever authorization you already trust, and tell the holder at the moment you show it that the key cannot be retrieved again.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Auth middleware factories for Express.
3
3
  *
4
- * Provides:
4
+ * `createAuthMiddleware` returns the app's middleware bundle:
5
5
  * - `resolveVisitor` — resolves req.user/sessionToken/visitorToken from auth_id/visitor_id
6
6
  * cookies if present. Never creates a user or sets cookies. If no cookie resolves,
7
7
  * req.user stays undefined so anonymous traffic does not mint user records.
@@ -11,9 +11,18 @@
11
11
  * Mints a user + visitor identity + session token and sets cookies on first call.
12
12
  * Idempotent: if resolveVisitor already populated req, returns the existing user.
13
13
  * - `requireAuth` — gates routes by trust tier, redirects web / 401s API.
14
+ * - `requireApiKey` — gates routes that must be reached with an API key specifically.
14
15
  * - `addAuthContext` — populates res.locals.auth for view templates.
16
+ *
17
+ * `createBearerMiddleware` is the standalone bearer resolver those share. It
18
+ * takes the lookup as an injected callback, so a capability that issues its own
19
+ * kind of token (oauth-server's access tokens) gets cap-users' bearer handling
20
+ * — header parsing, the refusal semantics, the fields written onto the request
21
+ * — without cap-users having to know what an OAuth token is. `resolveBearer` is
22
+ * that factory with `validateApiKey` injected, which is what keeps the two
23
+ * doors from drifting apart.
15
24
  */
16
- import type { Request, Response, NextFunction } from 'express';
25
+ import type { Request, RequestHandler, Response, NextFunction } from 'express';
17
26
  import type { AuthService } from './auth-service.js';
18
27
  import type { IdentityService } from './identity-service.js';
19
28
  import type { UserService } from './user-service.js';
@@ -45,6 +54,42 @@ export interface AuthMiddlewareOptions {
45
54
  */
46
55
  bearerChallenge?: string;
47
56
  }
57
+ /**
58
+ * Options for `createBearerMiddleware` — the three things that differ between
59
+ * one kind of bearer credential and another. Everything else about resolving a
60
+ * `Authorization: Bearer` header is the same for all of them, which is why they
61
+ * share an implementation.
62
+ */
63
+ export interface BearerMiddlewareOptions {
64
+ /**
65
+ * Resolve a presented token to its principal, or answer that it does not
66
+ * resolve. This is the whole identity domain in one callback: the caller
67
+ * decides which table the token lives in, what verification it needs, and
68
+ * which per-user conditions apply to it.
69
+ *
70
+ * Return `null` (or throw `AuthError`) for "this credential is not good" —
71
+ * both produce the 401. Throw anything else for "I could not tell" — a
72
+ * database being unreachable is not a bad token, and reporting it as one
73
+ * tells a correct client to discard a valid credential.
74
+ */
75
+ resolve: (token: string) => Promise<{
76
+ user: User<BaseUserInfo>;
77
+ } | null>;
78
+ /**
79
+ * Written to `req.authStrategy` on success — the label a downstream gate uses
80
+ * to tell one kind of credential from another. Use `'api-key'` only for an
81
+ * actual API key: `requireApiKey` gates on that exact literal, and reusing it
82
+ * for another credential walks that credential through the one gate whose
83
+ * purpose is to demand a key.
84
+ */
85
+ strategy: string;
86
+ /**
87
+ * The `WWW-Authenticate` value sent with the 401. A plain `'Bearer'` for an
88
+ * API key; a resource server that must point clients at its discovery
89
+ * document sends the fuller `Bearer resource_metadata="..."` form.
90
+ */
91
+ challenge: string;
92
+ }
48
93
  /** Shape of res.locals.auth populated by addAuthContext. */
49
94
  export interface AuthLocals {
50
95
  trustTier: TrustTier | null;
@@ -61,6 +106,55 @@ export interface AuthMiddleware {
61
106
  requireApiKey: (requiredTrust?: TrustTier) => (req: Request, res: Response, next: NextFunction) => void;
62
107
  addAuthContext: (req: Request, res: Response, next: NextFunction) => void;
63
108
  }
109
+ /**
110
+ * createBearerMiddleware — resolve `Authorization: Bearer <token>` through a
111
+ * caller-supplied lookup.
112
+ *
113
+ * Three outcomes, and the middle one is the design decision:
114
+ *
115
+ * - No `Authorization` header, or a scheme other than Bearer: pass through
116
+ * with req.user untouched, so this can be mounted on a router that also
117
+ * serves anonymous traffic. Gating is `requireAuth`'s job, not this one's.
118
+ * - A Bearer token that does not resolve: **401**, not silent anonymity. A
119
+ * caller that presented a credential and got it wrong should be told; a
120
+ * broken client that looks like a logged-out one is a bad afternoon.
121
+ * - A Bearer token that resolves: req.user is set to the same principal the
122
+ * cookie path yields, so everything downstream — requireAuth, trust tiers,
123
+ * res.locals.auth — works without knowing which door the request came in.
124
+ * It also records two more fields the cookie path does not:
125
+ * - req.sessionToken = the presented raw token. requireAuth reads BOTH
126
+ * req.user and req.sessionToken and denies if either is missing, so
127
+ * setting only req.user would make the published `resolveBearer` +
128
+ * `requireAuth` pairing deny every bearer request. On the API-key path
129
+ * sessionToken is also the `identityKey` requireAuth hands isAuthorized:
130
+ * `setAuthorization` hashes the key on the way in and `isAuthorized`
131
+ * hashes the presented one before comparing, so recording the RAW key
132
+ * here is what makes that comparison line up, and routing it through
133
+ * isAuthorized restores the per-key grant check ("expire the grant").
134
+ * - req.authStrategy = `options.strategy`, so a gate that must accept only
135
+ * one kind of credential (requireApiKey) can tell them apart. req.user
136
+ * alone cannot: resolveVisitor may have populated it from the cookie.
137
+ *
138
+ * It deliberately does **not** fall back to the session cookie when the token
139
+ * is bad. One of the donor codebases the oauth work drew on did fall back on
140
+ * a shared mount, and specs/oauth-server.spec.md names that as a shape not to
141
+ * lift: it means a request carrying a revoked key can still succeed, on the
142
+ * strength of a cookie the caller was not presenting as its credential. It is
143
+ * also why two bearer middlewares reading the same header is safe here and was
144
+ * not there — both refuse rather than fall through.
145
+ *
146
+ * Only outcomes that mean "this credential is not good" become 401s: a `null`
147
+ * from the resolver, or an `AuthError` thrown by it. Anything else (the
148
+ * database being unreachable, say) goes to next(err) so it is not misreported
149
+ * to the client as an auth failure.
150
+ *
151
+ * `deps` is not read here — resolution is entirely the caller's `resolve`
152
+ * callback — but it is part of the signature so that this factory and
153
+ * `createAuthMiddleware` are wired from the same object, and so a later
154
+ * addition that does need the services is not a breaking change for the
155
+ * capabilities already calling it.
156
+ */
157
+ export declare function createBearerMiddleware(deps: AuthMiddlewareDeps, options: BearerMiddlewareOptions): RequestHandler;
64
158
  /**
65
159
  * Create auth middleware functions wired to the auth, identity, and user services.
66
160
  */
@@ -1 +1 @@
1
- {"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../src/auth-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAMhE,uDAAuD;AACvD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CACxC;AAED,wCAAwC;AACxC,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1E,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACzE,eAAe,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9E,WAAW,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACtG,aAAa,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACxG,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC3E;AASD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,kBAAkB,EACxB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAkShB"}
1
+ {"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../src/auth-middleware.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Auth middleware factories for Express.
4
4
  *
5
- * Provides:
5
+ * `createAuthMiddleware` returns the app's middleware bundle:
6
6
  * - `resolveVisitor` — resolves req.user/sessionToken/visitorToken from auth_id/visitor_id
7
7
  * cookies if present. Never creates a user or sets cookies. If no cookie resolves,
8
8
  * req.user stays undefined so anonymous traffic does not mint user records.
@@ -12,9 +12,19 @@
12
12
  * Mints a user + visitor identity + session token and sets cookies on first call.
13
13
  * Idempotent: if resolveVisitor already populated req, returns the existing user.
14
14
  * - `requireAuth` — gates routes by trust tier, redirects web / 401s API.
15
+ * - `requireApiKey` — gates routes that must be reached with an API key specifically.
15
16
  * - `addAuthContext` — populates res.locals.auth for view templates.
17
+ *
18
+ * `createBearerMiddleware` is the standalone bearer resolver those share. It
19
+ * takes the lookup as an injected callback, so a capability that issues its own
20
+ * kind of token (oauth-server's access tokens) gets cap-users' bearer handling
21
+ * — header parsing, the refusal semantics, the fields written onto the request
22
+ * — without cap-users having to know what an OAuth token is. `resolveBearer` is
23
+ * that factory with `validateApiKey` injected, which is what keeps the two
24
+ * doors from drifting apart.
16
25
  */
17
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.createBearerMiddleware = createBearerMiddleware;
18
28
  exports.createAuthMiddleware = createAuthMiddleware;
19
29
  const logger_1 = require("@boopkit/logger");
20
30
  const auth_service_js_1 = require("./auth-service.js");
@@ -22,6 +32,93 @@ const logger = (0, logger_1.createLogger)('users', 'auth');
22
32
  // ---------- Constants ----------
23
33
  const ONE_YEAR_MS = 365 * 24 * 60 * 60 * 1000;
24
34
  const TEN_YEARS_MS = 10 * ONE_YEAR_MS;
35
+ // ---------- Bearer factory ----------
36
+ /**
37
+ * createBearerMiddleware — resolve `Authorization: Bearer <token>` through a
38
+ * caller-supplied lookup.
39
+ *
40
+ * Three outcomes, and the middle one is the design decision:
41
+ *
42
+ * - No `Authorization` header, or a scheme other than Bearer: pass through
43
+ * with req.user untouched, so this can be mounted on a router that also
44
+ * serves anonymous traffic. Gating is `requireAuth`'s job, not this one's.
45
+ * - A Bearer token that does not resolve: **401**, not silent anonymity. A
46
+ * caller that presented a credential and got it wrong should be told; a
47
+ * broken client that looks like a logged-out one is a bad afternoon.
48
+ * - A Bearer token that resolves: req.user is set to the same principal the
49
+ * cookie path yields, so everything downstream — requireAuth, trust tiers,
50
+ * res.locals.auth — works without knowing which door the request came in.
51
+ * It also records two more fields the cookie path does not:
52
+ * - req.sessionToken = the presented raw token. requireAuth reads BOTH
53
+ * req.user and req.sessionToken and denies if either is missing, so
54
+ * setting only req.user would make the published `resolveBearer` +
55
+ * `requireAuth` pairing deny every bearer request. On the API-key path
56
+ * sessionToken is also the `identityKey` requireAuth hands isAuthorized:
57
+ * `setAuthorization` hashes the key on the way in and `isAuthorized`
58
+ * hashes the presented one before comparing, so recording the RAW key
59
+ * here is what makes that comparison line up, and routing it through
60
+ * isAuthorized restores the per-key grant check ("expire the grant").
61
+ * - req.authStrategy = `options.strategy`, so a gate that must accept only
62
+ * one kind of credential (requireApiKey) can tell them apart. req.user
63
+ * alone cannot: resolveVisitor may have populated it from the cookie.
64
+ *
65
+ * It deliberately does **not** fall back to the session cookie when the token
66
+ * is bad. One of the donor codebases the oauth work drew on did fall back on
67
+ * a shared mount, and specs/oauth-server.spec.md names that as a shape not to
68
+ * lift: it means a request carrying a revoked key can still succeed, on the
69
+ * strength of a cookie the caller was not presenting as its credential. It is
70
+ * also why two bearer middlewares reading the same header is safe here and was
71
+ * not there — both refuse rather than fall through.
72
+ *
73
+ * Only outcomes that mean "this credential is not good" become 401s: a `null`
74
+ * from the resolver, or an `AuthError` thrown by it. Anything else (the
75
+ * database being unreachable, say) goes to next(err) so it is not misreported
76
+ * to the client as an auth failure.
77
+ *
78
+ * `deps` is not read here — resolution is entirely the caller's `resolve`
79
+ * callback — but it is part of the signature so that this factory and
80
+ * `createAuthMiddleware` are wired from the same object, and so a later
81
+ * addition that does need the services is not a breaking change for the
82
+ * capabilities already calling it.
83
+ */
84
+ function createBearerMiddleware(deps, options) {
85
+ const { resolve, strategy, challenge } = options;
86
+ void deps;
87
+ return function resolveBearerToken(req, res, next) {
88
+ const header = req.headers?.authorization;
89
+ if (typeof header !== 'string')
90
+ return next();
91
+ const match = /^Bearer +(.+)$/i.exec(header.trim());
92
+ if (!match)
93
+ return next();
94
+ const token = match[1].trim();
95
+ if (token === '')
96
+ return next();
97
+ const refuse = () => {
98
+ logger.warn('bearer token refused', { path: req.path, strategy });
99
+ res.set('WWW-Authenticate', challenge);
100
+ res.status(401).json({ error: 'invalid_token' });
101
+ };
102
+ // Promise.resolve().then wraps a resolver that throws synchronously, so a
103
+ // buggy caller cannot take the process down instead of reaching next(err).
104
+ Promise.resolve()
105
+ .then(() => resolve(token))
106
+ .then((resolved) => {
107
+ if (!resolved)
108
+ return refuse();
109
+ const r = req;
110
+ r.user = resolved.user;
111
+ r.sessionToken = token;
112
+ r.authStrategy = strategy;
113
+ next();
114
+ })
115
+ .catch((err) => {
116
+ if (!(err instanceof auth_service_js_1.AuthError))
117
+ return next(err);
118
+ refuse();
119
+ });
120
+ };
121
+ }
25
122
  // ---------- Factory ----------
26
123
  /**
27
124
  * Create auth middleware functions wired to the auth, identity, and user services.
@@ -45,73 +142,38 @@ function createAuthMiddleware(deps, options) {
45
142
  resolveFromCookies(req).then(() => next()).catch(next);
46
143
  }
47
144
  /**
48
- * resolveBearer — read-only resolver for `Authorization: Bearer <token>`.
145
+ * resolveBearer — the API-key instantiation of `createBearerMiddleware`.
49
146
  *
50
- * Three outcomes, and the middle one is the design decision:
147
+ * This is not a convenience wrapper around the general factory; it is the
148
+ * whole of the API-key bearer path. The spec's non-negotiable constraint for
149
+ * the OAuth widening was that the API-key path keep behaving exactly as it
150
+ * did, and building it out of the same factory the OAuth path uses makes that
151
+ * true by construction rather than by inspection: there is one bearer
152
+ * implementation, and every existing API-key test exercises it. Two parallel
153
+ * implementations that are supposed to agree is the arrangement that drifts.
51
154
  *
52
- * - No `Authorization` header, or a scheme other than Bearer: pass through
53
- * with req.user untouched, so this can be mounted on a router that also
54
- * serves anonymous traffic. Gating is `requireAuth`'s job, not this one's.
55
- * - A Bearer token that does not resolve: **401**, not silent anonymity. A
56
- * caller that presented a credential and got it wrong should be told; a
57
- * broken client that looks like a logged-out one is a bad afternoon.
58
- * - A Bearer token that resolves: req.user is set to the same principal the
59
- * cookie path yields, so everything downstream — requireAuth, trust tiers,
60
- * res.locals.auth — works without knowing which door the request came in.
61
- * It also records two more fields the cookie path does not:
62
- * - req.sessionToken = the presented raw key. requireAuth reads BOTH
63
- * req.user and req.sessionToken and denies if either is missing, so
64
- * setting only req.user would make the published `resolveBearer` +
65
- * `requireAuth` pairing deny every bearer request. sessionToken is also
66
- * the `identityKey` requireAuth hands isAuthorized, and createApiKey
67
- * records the per-key grant under the RAW key — so the presented key is
68
- * exactly what that call is asking for, and routing it through
69
- * isAuthorized restores the per-key grant check ("expire the grant") for
70
- * free. COUPLING: this relies on createApiKey keying the grant on the
71
- * raw key (auth-service.ts, `setAuthorization(userId, apiKey, ...)`).
72
- * boop-owbv proposes hashing that field; whichever of the two lands
73
- * second MUST update the other or API-key authorization breaks silently.
74
- * - req.authStrategy = 'api-key', so a gate that must accept ONLY a key
75
- * (requireApiKey) can tell a key principal from a cookie one. req.user
76
- * alone cannot: resolveVisitor may have populated it from the cookie.
155
+ * The three injected pieces are the whole of what makes this path the
156
+ * API-key one:
77
157
  *
78
- * It deliberately does **not** fall back to the session cookie when the token
79
- * is bad. One of the donor codebases the oauth work drew on did fall back on
80
- * a shared mount, and specs/oauth-server.spec.md names that as a shape not to
81
- * lift: it means a request carrying a revoked key can still succeed, on the
82
- * strength of a cookie the caller was not presenting as its credential.
158
+ * - `validateApiKey` as the resolver. It does four things an OAuth token
159
+ * would fail three of — the hardcoded `'api-key'` identity domain, a bcrypt
160
+ * check against the user's `credentials` property, an
161
+ * `isMethodAccepted(userId, 'api-key')` check against their `authentication`
162
+ * property, and the lookup itself — which is exactly why the seam is a
163
+ * callback rather than a `domain` option. It signals a bad key by throwing
164
+ * `AuthError`, which the factory treats as a refusal.
165
+ * - `'api-key'` as the strategy label, the literal `requireApiKey` gates on.
166
+ * - `bearerChallenge` as the `WWW-Authenticate` value, so an app can still
167
+ * override the challenge through `createAuthMiddleware`'s options.
83
168
  *
84
- * Only errors that mean "this credential is not good" become 401s; anything
85
- * else (the database being unreachable, say) goes to next(err) so it is not
86
- * misreported to the client as an auth failure.
169
+ * See `createBearerMiddleware` above for the resolution semantics and for why
170
+ * a bad token refuses rather than falling through to the session cookie.
87
171
  */
88
- function resolveBearer(req, res, next) {
89
- const header = req.headers?.authorization;
90
- if (typeof header !== 'string')
91
- return next();
92
- const match = /^Bearer +(.+)$/i.exec(header.trim());
93
- if (!match)
94
- return next();
95
- const token = match[1].trim();
96
- if (token === '')
97
- return next();
98
- authService
99
- .validateApiKey(token)
100
- .then((user) => {
101
- const r = req;
102
- r.user = user;
103
- r.sessionToken = token;
104
- r.authStrategy = 'api-key';
105
- next();
106
- })
107
- .catch((err) => {
108
- if (!(err instanceof auth_service_js_1.AuthError))
109
- return next(err);
110
- logger.warn('bearer token refused', { path: req.path });
111
- res.set('WWW-Authenticate', bearerChallenge);
112
- res.status(401).json({ error: 'invalid_token' });
113
- });
114
- }
172
+ const resolveBearer = createBearerMiddleware(deps, {
173
+ resolve: (token) => authService.validateApiKey(token).then((user) => ({ user })),
174
+ strategy: 'api-key',
175
+ challenge: bearerChallenge,
176
+ });
115
177
  async function resolveFromCookies(req) {
116
178
  let user;
117
179
  let sessionToken;
@@ -221,6 +283,12 @@ function createAuthMiddleware(deps, options) {
221
283
  const user = req.user;
222
284
  const sessionToken = req.sessionToken;
223
285
  const authStrategy = req.authStrategy;
286
+ // The comparison stays on the 'api-key' LITERAL even though the field's
287
+ // declared type widened to string. That is the point of the widening:
288
+ // another capability may label its own bearer path 'oauth', and this gate
289
+ // exists to demand an independently revocable API key specifically, so an
290
+ // OAuth access token has to fail here by construction rather than by
291
+ // somebody remembering to check.
224
292
  if (!user || !sessionToken || authStrategy !== 'api-key') {
225
293
  res.set('WWW-Authenticate', bearerChallenge).status(401).json({ error: 'Unauthorized' });
226
294
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../src/auth-middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../src/auth-middleware.ts"],"names":[],"mappings":"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"}
@@ -9,12 +9,57 @@ export interface IdentityServiceOptions {
9
9
  export interface IdentityQueryOptions {
10
10
  includeEnded?: boolean;
11
11
  }
12
+ /** Rows per page when a key-prefix scan is not told otherwise. */
13
+ export declare const IDENTITY_PREFIX_PAGE_SIZE = 100;
14
+ /** The most a single page of a key-prefix scan will return, however asked. */
15
+ export declare const IDENTITY_PREFIX_MAX_PAGE_SIZE = 500;
16
+ /** Options for the key-prefix scan. */
17
+ export interface IdentityPrefixQueryOptions extends IdentityQueryOptions {
18
+ /**
19
+ * Rows in this page. Defaults to `IDENTITY_PREFIX_PAGE_SIZE` and is clamped
20
+ * to `IDENTITY_PREFIX_MAX_PAGE_SIZE`, so a caller cannot turn the scan into
21
+ * the whole-table read it exists to avoid.
22
+ */
23
+ limit?: number;
24
+ /** Exclusive cursor — the previous page's `nextCursor`. */
25
+ after?: number;
26
+ }
27
+ /** One page of a key-prefix scan. */
28
+ export interface IdentityPrefixPage {
29
+ identities: UserIdentity[];
30
+ /**
31
+ * Feed back as `after` to continue. `null` when this page ended the scan.
32
+ *
33
+ * A full page always answers with a cursor, even when it happened to be the
34
+ * last one, so the caller's final request is an empty page rather than a
35
+ * count the query cannot know without a second read.
36
+ */
37
+ nextCursor: number | null;
38
+ }
12
39
  /** The service object returned by createIdentityService. */
13
40
  export interface IdentityService {
14
41
  create(userId: number, domain: string, key: string): Promise<UserIdentity>;
15
42
  findByDomainAndKey(domain: string, key: string): Promise<UserIdentity | null>;
16
43
  findByUserAndDomain(userId: number, domain: string): Promise<UserIdentity | null>;
17
44
  findAllByUser(userId: number, opts?: IdentityQueryOptions): Promise<UserIdentity[]>;
45
+ /**
46
+ * One page of the rows in `domain` whose key starts with `keyPrefix`, in id
47
+ * order, for any user.
48
+ *
49
+ * This is the only read here that is not bounded by a user id, and it exists
50
+ * for one job: a credential domain whose keys are `"<issuer>|<secret hash>"`
51
+ * — cap-oauth-server's token rows — needs to enumerate everybody one issuer
52
+ * ever reached, so that a compromised client can be retired without the
53
+ * operator already knowing which accounts to sweep.
54
+ *
55
+ * Both narrowings are load-bearing rather than conveniences. The **domain is
56
+ * required** so the scan cannot wander into `email` or `api-key` rows, and an
57
+ * **empty prefix is refused** because it would walk a whole domain — which is
58
+ * the read this method is shaped to make unnecessary. Left-anchored, the
59
+ * comparison is a seek on the `(domain, key)` unique index rather than a
60
+ * table scan, which is the whole reason the key format puts the issuer first.
61
+ */
62
+ findAllByDomainAndKeyPrefix(domain: string, keyPrefix: string, opts?: IdentityPrefixQueryOptions): Promise<IdentityPrefixPage>;
18
63
  update(domain: string, key: string, newUserId: number): Promise<UserIdentity>;
19
64
  endDate(domain: string, key: string): Promise<UserIdentity>;
20
65
  }
@@ -31,6 +76,10 @@ interface IdentityDelegate {
31
76
  }): Promise<Record<string, unknown> | null>;
32
77
  findMany(args: {
33
78
  where: Record<string, unknown>;
79
+ orderBy?: {
80
+ id?: 'asc' | 'desc';
81
+ };
82
+ take?: number;
34
83
  }): Promise<Record<string, unknown>[]>;
35
84
  update(args: {
36
85
  where: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"identity-service.d.ts","sourceRoot":"","sources":["../src/identity-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,kDAAkD;AAClD,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC;AAED,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3E,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAC9E,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAClF,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACpF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC7D;AAED,kEAAkE;AAClE,UAAU,gBAAgB;IACxB,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9F,SAAS,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7F,QAAQ,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACvF,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnH;AAkCD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,eAAe,CA8DjB"}
1
+ {"version":3,"file":"identity-service.d.ts","sourceRoot":"","sources":["../src/identity-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,kDAAkD;AAClD,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC;AAED,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,kEAAkE;AAClE,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,uCAAuC;AACvC,MAAM,WAAW,0BAA2B,SAAQ,oBAAoB;IACtE;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3E,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAC9E,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAClF,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACpF;;;;;;;;;;;;;;;;OAgBG;IACH,2BAA2B,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,0BAA0B,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC7D;AAED,kEAAkE;AAClE,UAAU,gBAAgB;IACxB,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9F,SAAS,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7F,QAAQ,CAAC,IAAI,EAAE;QACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE;YAAE,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;SAAE,CAAC;QAClC,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnH;AAkCD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,eAAe,CA2GjB"}
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IDENTITY_PREFIX_MAX_PAGE_SIZE = exports.IDENTITY_PREFIX_PAGE_SIZE = void 0;
3
4
  exports.createIdentityService = createIdentityService;
4
5
  const types_js_1 = require("./types.js");
6
+ /** Rows per page when a key-prefix scan is not told otherwise. */
7
+ exports.IDENTITY_PREFIX_PAGE_SIZE = 100;
8
+ /** The most a single page of a key-prefix scan will return, however asked. */
9
+ exports.IDENTITY_PREFIX_MAX_PAGE_SIZE = 500;
5
10
  function toIdentity(row) {
6
11
  const endedAt = row.endedAt;
7
12
  return {
@@ -75,6 +80,35 @@ function createIdentityService(model, options) {
75
80
  const rows = await model.findMany({ where });
76
81
  return rows.map(toIdentity);
77
82
  },
83
+ async findAllByDomainAndKeyPrefix(domain, keyPrefix, opts) {
84
+ if (!domain) {
85
+ throw new TypeError('Unable to scan identities by key prefix: no domain was given. ' +
86
+ 'Pass the identity domain to scan, such as "oauth-access".');
87
+ }
88
+ if (!keyPrefix) {
89
+ throw new TypeError(`Unable to scan identities by key prefix: the prefix was empty, which would read every "${domain}" row. ` +
90
+ 'Pass the prefix to match, or use findAllByUser for one user\'s identities.');
91
+ }
92
+ const limit = Math.min(Math.max(1, Math.trunc(opts?.limit ?? exports.IDENTITY_PREFIX_PAGE_SIZE)), exports.IDENTITY_PREFIX_MAX_PAGE_SIZE);
93
+ const where = {
94
+ domain,
95
+ key: { startsWith: normalizeKey(domain, keyPrefix) },
96
+ };
97
+ if (!opts?.includeEnded) {
98
+ where.endedAt = null;
99
+ }
100
+ // The cursor is the row id rather than an offset: pages are stable under
101
+ // rows arriving mid-scan, which for a token table is every request.
102
+ if (opts?.after != null) {
103
+ where.id = { gt: opts.after };
104
+ }
105
+ const rows = await model.findMany({ where, orderBy: { id: 'asc' }, take: limit });
106
+ const identities = rows.map(toIdentity);
107
+ return {
108
+ identities,
109
+ nextCursor: identities.length === limit ? identities[identities.length - 1].id : null,
110
+ };
111
+ },
78
112
  async update(domain, key, newUserId) {
79
113
  const row = await model.update({
80
114
  where: domainKeyWhere(domain, normalizeKey(domain, key)),
@@ -1 +1 @@
1
- {"version":3,"file":"identity-service.js","sourceRoot":"","sources":["../src/identity-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identity-service.js","sourceRoot":"","sources":["../src/identity-service.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -9,13 +9,14 @@ export type { BaseUserInfo, User, UserIdentity, UserProfile, CredentialEntry, Us
9
9
  export { createUserService } from './user-service.js';
10
10
  export type { UserService, UserServiceOptions } from './user-service.js';
11
11
  export { createIdentityService } from './identity-service.js';
12
- export type { IdentityService, IdentityServiceOptions, IdentityQueryOptions } from './identity-service.js';
12
+ export { IDENTITY_PREFIX_PAGE_SIZE, IDENTITY_PREFIX_MAX_PAGE_SIZE, } from './identity-service.js';
13
+ export type { IdentityService, IdentityServiceOptions, IdentityQueryOptions, IdentityPrefixQueryOptions, IdentityPrefixPage, } from './identity-service.js';
13
14
  export { createUserPropertyService } from './user-property-service.js';
14
15
  export type { UserPropertyService, UserPropertyServiceOptions } from './user-property-service.js';
15
16
  export { createAuthService, AuthValidationError, AuthError, generateToken, hashToken, isHashedToken } from './auth-service.js';
16
17
  export type { AuthService, AuthServiceDeps, AuthServiceOptions, AddAuthMethodOptions, SignupInput, SignupResult, LoginResult, VerifyEmailResult, } from './auth-service.js';
17
- export { createAuthMiddleware } from './auth-middleware.js';
18
- export type { AuthMiddleware, AuthMiddlewareDeps, AuthMiddlewareOptions, AuthLocals, } from './auth-middleware.js';
18
+ export { createAuthMiddleware, createBearerMiddleware } from './auth-middleware.js';
19
+ export type { AuthMiddleware, AuthMiddlewareDeps, AuthMiddlewareOptions, BearerMiddlewareOptions, AuthLocals, } from './auth-middleware.js';
19
20
  export { createAccountService } from './account-service.js';
20
21
  export type { AccountService, AccountServiceOptions } from './account-service.js';
21
22
  export { createAccountPropertyService } from './account-property-service.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,OAAO,EACP,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE3G,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/H,YAAY,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElF,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,YAAY,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAE3G,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,+BAA+B,EAC/B,qBAAqB,EACrB,sBAAsB,EACtB,UAAU,GACX,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,GACZ,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GAChB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,gCAAgC,EAChC,mCAAmC,GACpC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,OAAO,EACP,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/H,YAAY,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACpF,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElF,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,YAAY,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAE3G,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,+BAA+B,EAC/B,qBAAqB,EACrB,sBAAsB,EACtB,UAAU,GACX,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,GACZ,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GAChB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,gCAAgC,EAChC,mCAAmC,GACpC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * composing on top of @boopkit/cap-services primitives.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.teamInvitationsStore = exports.rehashTeamInvitations = exports.authorizationStore = exports.rehashAuthorizationGrants = exports.migrateCredentialStore = exports.TEAM_INVITATIONS_HASHED_INFO_SCHEMA = exports.AUTHORIZATION_HASHED_INFO_SCHEMA = exports.MAX_RESENDS = exports.MAX_PENDING_INVITATIONS = exports.DEFAULT_INVITATION_TTL_MS = exports.TeamInvitationError = exports.createTeamInvitationService = exports.AccountManagementError = exports.createAccountManagementService = exports.createAccountPropertyService = exports.createAccountService = exports.createAuthMiddleware = exports.isHashedToken = exports.hashToken = exports.generateToken = exports.AuthError = exports.AuthValidationError = exports.createAuthService = exports.createUserPropertyService = exports.createIdentityService = exports.createUserService = exports.DuplicateAccountUserError = exports.DuplicateIdentityError = void 0;
9
+ exports.teamInvitationsStore = exports.rehashTeamInvitations = exports.authorizationStore = exports.rehashAuthorizationGrants = exports.migrateCredentialStore = exports.TEAM_INVITATIONS_HASHED_INFO_SCHEMA = exports.AUTHORIZATION_HASHED_INFO_SCHEMA = exports.MAX_RESENDS = exports.MAX_PENDING_INVITATIONS = exports.DEFAULT_INVITATION_TTL_MS = exports.TeamInvitationError = exports.createTeamInvitationService = exports.AccountManagementError = exports.createAccountManagementService = exports.createAccountPropertyService = exports.createAccountService = exports.createBearerMiddleware = exports.createAuthMiddleware = exports.isHashedToken = exports.hashToken = exports.generateToken = exports.AuthError = exports.AuthValidationError = exports.createAuthService = exports.createUserPropertyService = exports.IDENTITY_PREFIX_MAX_PAGE_SIZE = exports.IDENTITY_PREFIX_PAGE_SIZE = exports.createIdentityService = exports.createUserService = exports.DuplicateAccountUserError = exports.DuplicateIdentityError = void 0;
10
10
  var types_js_1 = require("./types.js");
11
11
  Object.defineProperty(exports, "DuplicateIdentityError", { enumerable: true, get: function () { return types_js_1.DuplicateIdentityError; } });
12
12
  Object.defineProperty(exports, "DuplicateAccountUserError", { enumerable: true, get: function () { return types_js_1.DuplicateAccountUserError; } });
@@ -14,6 +14,9 @@ var user_service_js_1 = require("./user-service.js");
14
14
  Object.defineProperty(exports, "createUserService", { enumerable: true, get: function () { return user_service_js_1.createUserService; } });
15
15
  var identity_service_js_1 = require("./identity-service.js");
16
16
  Object.defineProperty(exports, "createIdentityService", { enumerable: true, get: function () { return identity_service_js_1.createIdentityService; } });
17
+ var identity_service_js_2 = require("./identity-service.js");
18
+ Object.defineProperty(exports, "IDENTITY_PREFIX_PAGE_SIZE", { enumerable: true, get: function () { return identity_service_js_2.IDENTITY_PREFIX_PAGE_SIZE; } });
19
+ Object.defineProperty(exports, "IDENTITY_PREFIX_MAX_PAGE_SIZE", { enumerable: true, get: function () { return identity_service_js_2.IDENTITY_PREFIX_MAX_PAGE_SIZE; } });
17
20
  var user_property_service_js_1 = require("./user-property-service.js");
18
21
  Object.defineProperty(exports, "createUserPropertyService", { enumerable: true, get: function () { return user_property_service_js_1.createUserPropertyService; } });
19
22
  var auth_service_js_1 = require("./auth-service.js");
@@ -25,6 +28,7 @@ Object.defineProperty(exports, "hashToken", { enumerable: true, get: function ()
25
28
  Object.defineProperty(exports, "isHashedToken", { enumerable: true, get: function () { return auth_service_js_1.isHashedToken; } });
26
29
  var auth_middleware_js_1 = require("./auth-middleware.js");
27
30
  Object.defineProperty(exports, "createAuthMiddleware", { enumerable: true, get: function () { return auth_middleware_js_1.createAuthMiddleware; } });
31
+ Object.defineProperty(exports, "createBearerMiddleware", { enumerable: true, get: function () { return auth_middleware_js_1.createBearerMiddleware; } });
28
32
  var account_service_js_1 = require("./account-service.js");
29
33
  Object.defineProperty(exports, "createAccountService", { enumerable: true, get: function () { return account_service_js_1.createAccountService; } });
30
34
  var account_property_service_js_1 = require("./account-property-service.js");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,uCAA+E;AAAtE,kHAAA,sBAAsB,OAAA;AAAE,qHAAA,yBAAyB,OAAA;AAmB1D,qDAAsD;AAA7C,oHAAA,iBAAiB,OAAA;AAG1B,6DAA8D;AAArD,4HAAA,qBAAqB,OAAA;AAG9B,uEAAuE;AAA9D,qIAAA,yBAAyB,OAAA;AAGlC,qDAA+H;AAAtH,oHAAA,iBAAiB,OAAA;AAAE,sHAAA,mBAAmB,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAYnG,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAQ7B,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAG7B,6EAA6E;AAApE,2IAAA,4BAA4B,OAAA;AAGrC,iFAAyG;AAAhG,+IAAA,8BAA8B,OAAA;AAAE,uIAAA,sBAAsB,OAAA;AAU/D,2EAMsC;AALpC,yIAAA,2BAA2B,OAAA;AAC3B,iIAAA,mBAAmB,OAAA;AACnB,uIAAA,yBAAyB,OAAA;AACzB,qIAAA,uBAAuB,OAAA;AACvB,yHAAA,WAAW,OAAA;AAWb,6DAG+B;AAF7B,uIAAA,gCAAgC,OAAA;AAChC,0IAAA,mCAAmC,OAAA;AAGrC,qEAMmC;AALjC,iIAAA,sBAAsB,OAAA;AACtB,oIAAA,yBAAyB,OAAA;AACzB,6HAAA,kBAAkB,OAAA;AAClB,gIAAA,qBAAqB,OAAA;AACrB,+HAAA,oBAAoB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,uCAA+E;AAAtE,kHAAA,sBAAsB,OAAA;AAAE,qHAAA,yBAAyB,OAAA;AAmB1D,qDAAsD;AAA7C,oHAAA,iBAAiB,OAAA;AAG1B,6DAA8D;AAArD,4HAAA,qBAAqB,OAAA;AAC9B,6DAG+B;AAF7B,gIAAA,yBAAyB,OAAA;AACzB,oIAAA,6BAA6B,OAAA;AAU/B,uEAAuE;AAA9D,qIAAA,yBAAyB,OAAA;AAGlC,qDAA+H;AAAtH,oHAAA,iBAAiB,OAAA;AAAE,sHAAA,mBAAmB,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAYnG,2DAAoF;AAA3E,0HAAA,oBAAoB,OAAA;AAAE,4HAAA,sBAAsB,OAAA;AASrD,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAG7B,6EAA6E;AAApE,2IAAA,4BAA4B,OAAA;AAGrC,iFAAyG;AAAhG,+IAAA,8BAA8B,OAAA;AAAE,uIAAA,sBAAsB,OAAA;AAU/D,2EAMsC;AALpC,yIAAA,2BAA2B,OAAA;AAC3B,iIAAA,mBAAmB,OAAA;AACnB,uIAAA,yBAAyB,OAAA;AACzB,qIAAA,uBAAuB,OAAA;AACvB,yHAAA,WAAW,OAAA;AAWb,6DAG+B;AAF7B,uIAAA,gCAAgC,OAAA;AAChC,0IAAA,mCAAmC,OAAA;AAGrC,qEAMmC;AALjC,iIAAA,sBAAsB,OAAA;AACtB,oIAAA,yBAAyB,OAAA;AACzB,6HAAA,kBAAkB,OAAA;AAClB,gIAAA,qBAAqB,OAAA;AACrB,+HAAA,oBAAoB,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boopkit/cap-users",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "User accounts, authentication, and session management via Prisma",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -159,6 +159,10 @@ A request with no `Authorization` header passes through with `req.user` unset, s
159
159
  A token that does not resolve gets `401 { error: 'invalid_token' }` and a `WWW-Authenticate` challenge, and does **not** fall back to the session cookie — revoking a key has to stop the request even from a browser that is still logged in.
160
160
  It refuses a malformed token on every route it covers, open ones included, which is why the health check is mounted ahead of it: a route registered before `resolveBearer` never sees the middleware, so a monitor carrying a stale or garbled `Authorization` header still gets its `200` rather than a `401`.
161
161
 
162
+ `resolveBearer` is itself `createBearerMiddleware(deps, { resolve, strategy, challenge })` — exported from `@boopkit/cap-users` — with `validateApiKey` as the resolver and `'api-key'` as the strategy.
163
+ If your app issues another kind of bearer token, build a second middleware from that factory rather than writing one: you get the same parsing and the same refusal semantics, and both doors refuse instead of falling through to the cookie, which is what makes two of them safe on one header.
164
+ Give it its own strategy label — `req.authStrategy` is typed `string` so you can — because `requireApiKey` gates on the `'api-key'` literal, and reusing that label would let your token through the one gate that exists to demand a key.
165
+
162
166
  **Issuing a key is yours to design.**
163
167
  `authService.createApiKey(userId)` mints one and returns the raw key exactly once; the identity row holds its SHA-256 and the credentials entry a bcrypt hash, so nothing can hand it back later and any surface you build has to say so at the moment it is shown.
164
168
  This capability deliberately ships no route, screen, or command for it.
@@ -242,6 +246,32 @@ All services compose from `@boopkit/cap-services` primitives:
242
246
  | `userPropertyService` | `createUserPropertyService()` | Read/write user properties (credentials gated) |
243
247
  | `authService` | `createAuthService(deps, opts)` | Orchestrates signup, login, sessions, API keys |
244
248
 
249
+ ### IdentityService reads
250
+
251
+ Every read is bounded by a user id or an exact `(domain, key)` pair — except one.
252
+
253
+ `findAllByDomainAndKeyPrefix(domain, keyPrefix, opts?)` returns one page of the rows in a single
254
+ domain whose key starts with `keyPrefix`, for **any** user, in id order:
255
+
256
+ ```ts
257
+ const page = await identityService.findAllByDomainAndKeyPrefix('oauth-access', `${publicId}|`, {
258
+ includeEnded: true,
259
+ limit: 100, // clamped to 500
260
+ after: previousPage.nextCursor ?? undefined,
261
+ });
262
+ ```
263
+
264
+ It exists for credential domains whose keys are `"<issuer>|<secret hash>"` — cap-oauth-server's
265
+ token rows — where retiring one issuer means finding everybody it ever reached, and the operator
266
+ should not have to know the blast radius in advance. Left-anchored, the comparison is a seek on the
267
+ `(domain, key)` unique index rather than a table scan.
268
+
269
+ Both narrowings are load-bearing rather than ergonomic. The **domain is required**, so the scan
270
+ cannot wander into `email` or `api-key` rows; an **empty prefix throws**, because it would walk a
271
+ whole domain, which is the read this method exists to make unnecessary. It **pages** rather than
272
+ materialising a result set of unknown size: keep passing `nextCursor` back as `after` until it comes
273
+ back `null`.
274
+
245
275
  ### AuthService key operations
246
276
 
247
277
  **Signup**: `signup({ email, password, name })` — creates user, email identity, profile, credentials, auth method, session token, and authorization grant in one call. Each step is also available individually for graduated control.
@@ -60,8 +60,18 @@ declare global {
60
60
  * the session cookie via resolveVisitor. A gate that must accept only one
61
61
  * kind of credential (requireApiKey) reads this — req.user alone cannot
62
62
  * tell a key principal from a cookie one.
63
+ *
64
+ * `string`, not the `'api-key'` literal, because the label is chosen by
65
+ * whoever built the bearer middleware: `createBearerMiddleware` writes
66
+ * whatever `options.strategy` it was given, so a capability that issues
67
+ * its own tokens labels them its own way (oauth-server uses `'oauth'`).
68
+ * cap-users' own `resolveBearer` still writes `'api-key'`, and
69
+ * `requireApiKey` still compares against that literal — which is what
70
+ * makes another capability's token fail a key-only gate rather than pass
71
+ * it. Widening the label and widening the gate are NOT the same change;
72
+ * only the label widens.
63
73
  */
64
- authStrategy?: 'api-key';
74
+ authStrategy?: string;
65
75
  }
66
76
  }
67
77
  }