@boopkit/cap-oauth-server 0.1.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.
Files changed (124) hide show
  1. package/capability.json +120 -0
  2. package/dist/authorization-code-service.d.ts +105 -0
  3. package/dist/authorization-code-service.d.ts.map +1 -0
  4. package/dist/authorization-code-service.js +142 -0
  5. package/dist/authorization-code-service.js.map +1 -0
  6. package/dist/bearer.d.ts +146 -0
  7. package/dist/bearer.d.ts.map +1 -0
  8. package/dist/bearer.js +150 -0
  9. package/dist/bearer.js.map +1 -0
  10. package/dist/body-field.d.ts +24 -0
  11. package/dist/body-field.d.ts.map +1 -0
  12. package/dist/body-field.js +43 -0
  13. package/dist/body-field.js.map +1 -0
  14. package/dist/client-registry-service.d.ts +120 -0
  15. package/dist/client-registry-service.d.ts.map +1 -0
  16. package/dist/client-registry-service.js +450 -0
  17. package/dist/client-registry-service.js.map +1 -0
  18. package/dist/config.d.ts +82 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +157 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/connections-controller.d.ts +106 -0
  23. package/dist/connections-controller.d.ts.map +1 -0
  24. package/dist/connections-controller.js +161 -0
  25. package/dist/connections-controller.js.map +1 -0
  26. package/dist/consent-controller.d.ts +197 -0
  27. package/dist/consent-controller.d.ts.map +1 -0
  28. package/dist/consent-controller.js +532 -0
  29. package/dist/consent-controller.js.map +1 -0
  30. package/dist/discovery-controller.d.ts +16 -0
  31. package/dist/discovery-controller.d.ts.map +1 -0
  32. package/dist/discovery-controller.js +52 -0
  33. package/dist/discovery-controller.js.map +1 -0
  34. package/dist/discovery.d.ts +95 -0
  35. package/dist/discovery.d.ts.map +1 -0
  36. package/dist/discovery.js +101 -0
  37. package/dist/discovery.js.map +1 -0
  38. package/dist/errors.d.ts +26 -0
  39. package/dist/errors.d.ts.map +1 -0
  40. package/dist/errors.js +41 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/express.d.ts +66 -0
  43. package/dist/express.d.ts.map +1 -0
  44. package/dist/express.js +3 -0
  45. package/dist/express.js.map +1 -0
  46. package/dist/grant-service.d.ts +102 -0
  47. package/dist/grant-service.d.ts.map +1 -0
  48. package/dist/grant-service.js +137 -0
  49. package/dist/grant-service.js.map +1 -0
  50. package/dist/index.d.ts +67 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +148 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/metadata-document.d.ts +60 -0
  55. package/dist/metadata-document.d.ts.map +1 -0
  56. package/dist/metadata-document.js +148 -0
  57. package/dist/metadata-document.js.map +1 -0
  58. package/dist/oauth-error.d.ts +45 -0
  59. package/dist/oauth-error.d.ts.map +1 -0
  60. package/dist/oauth-error.js +51 -0
  61. package/dist/oauth-error.js.map +1 -0
  62. package/dist/pkce.d.ts +29 -0
  63. package/dist/pkce.d.ts.map +1 -0
  64. package/dist/pkce.js +65 -0
  65. package/dist/pkce.js.map +1 -0
  66. package/dist/property-array.d.ts +60 -0
  67. package/dist/property-array.d.ts.map +1 -0
  68. package/dist/property-array.js +31 -0
  69. package/dist/property-array.js.map +1 -0
  70. package/dist/public-id.d.ts +35 -0
  71. package/dist/public-id.d.ts.map +1 -0
  72. package/dist/public-id.js +76 -0
  73. package/dist/public-id.js.map +1 -0
  74. package/dist/rate-limit.d.ts +56 -0
  75. package/dist/rate-limit.d.ts.map +1 -0
  76. package/dist/rate-limit.js +55 -0
  77. package/dist/rate-limit.js.map +1 -0
  78. package/dist/redirect-uri.d.ts +89 -0
  79. package/dist/redirect-uri.d.ts.map +1 -0
  80. package/dist/redirect-uri.js +249 -0
  81. package/dist/redirect-uri.js.map +1 -0
  82. package/dist/registration-controller.d.ts +62 -0
  83. package/dist/registration-controller.d.ts.map +1 -0
  84. package/dist/registration-controller.js +79 -0
  85. package/dist/registration-controller.js.map +1 -0
  86. package/dist/request-client.d.ts +19 -0
  87. package/dist/request-client.d.ts.map +1 -0
  88. package/dist/request-client.js +32 -0
  89. package/dist/request-client.js.map +1 -0
  90. package/dist/revocation-controller.d.ts +28 -0
  91. package/dist/revocation-controller.d.ts.map +1 -0
  92. package/dist/revocation-controller.js +176 -0
  93. package/dist/revocation-controller.js.map +1 -0
  94. package/dist/revocation-service.d.ts +113 -0
  95. package/dist/revocation-service.d.ts.map +1 -0
  96. package/dist/revocation-service.js +121 -0
  97. package/dist/revocation-service.js.map +1 -0
  98. package/dist/token-controller.d.ts +79 -0
  99. package/dist/token-controller.d.ts.map +1 -0
  100. package/dist/token-controller.js +207 -0
  101. package/dist/token-controller.js.map +1 -0
  102. package/dist/token-service.d.ts +175 -0
  103. package/dist/token-service.d.ts.map +1 -0
  104. package/dist/token-service.js +251 -0
  105. package/dist/token-service.js.map +1 -0
  106. package/dist/types.d.ts +130 -0
  107. package/dist/types.d.ts.map +1 -0
  108. package/dist/types.js +13 -0
  109. package/dist/types.js.map +1 -0
  110. package/dist/user-store.d.ts +110 -0
  111. package/dist/user-store.d.ts.map +1 -0
  112. package/dist/user-store.js +40 -0
  113. package/dist/user-store.js.map +1 -0
  114. package/package.json +37 -0
  115. package/scaffold/prisma/schema/oauth-clients.prisma +80 -0
  116. package/scaffold/reference/oauth-server.ref.md +478 -0
  117. package/scaffold/src/middleware/oauth-server.ts +227 -0
  118. package/scaffold/src/scripts/seed-oauth-clients.ts +72 -0
  119. package/scaffold/src/services/oauth-server.service.ts +101 -0
  120. package/scaffold/styles/oauth-server.css +345 -0
  121. package/scaffold/views/oauth-connected-clients.hbs +98 -0
  122. package/scaffold/views/oauth-consent-error.hbs +22 -0
  123. package/scaffold/views/oauth-consent.hbs +138 -0
  124. package/scaffold/views/oauth-disconnect-confirm.hbs +57 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-service.js","sourceRoot":"","sources":["../src/token-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The client registry's vocabulary.
3
+ *
4
+ * Everything here describes a piece of *software* that asks to act on a user's
5
+ * behalf. Nothing here describes a user or an account — those live in cap-users
6
+ * and are reached only through its public surface. Keeping the two vocabularies
7
+ * apart is what stops OAuth from becoming a parallel identity system.
8
+ */
9
+ /** Where a client's authoritative metadata lives. */
10
+ export type ClientMode = 'dynamic' | 'metadata_document' | 'static';
11
+ /** Whether the registry will let a client through the token path at all. */
12
+ export type ClientStatus = 'enabled' | 'suspended';
13
+ export declare const CLIENT_MODES: readonly ClientMode[];
14
+ /**
15
+ * A registry row, as the rest of the capability reads it.
16
+ *
17
+ * The JSON columns arrive from Prisma as `JsonValue`; the service casts them to
18
+ * these shapes on the way out, so no consumer has to.
19
+ */
20
+ export interface OauthClient {
21
+ id: number;
22
+ /** The token prefix. See `src/public-id.ts`. */
23
+ publicId: string;
24
+ /** What the client sends as `client_id`. A URL, for `metadata_document`. */
25
+ clientId: string;
26
+ mode: ClientMode;
27
+ status: ClientStatus;
28
+ name: string | null;
29
+ description: string | null;
30
+ logoUri: string | null;
31
+ clientUri: string | null;
32
+ contacts: string[];
33
+ softwareId: string | null;
34
+ softwareVersion: string | null;
35
+ policyUri: string | null;
36
+ tosUri: string | null;
37
+ redirectUris: string[];
38
+ grantTypes: string[];
39
+ responseTypes: string[];
40
+ scopes: string[];
41
+ tokenEndpointAuthMethod: string;
42
+ metadataUri: string | null;
43
+ metadataFetchedAt: Date | null;
44
+ createdAt: Date;
45
+ updatedAt: Date;
46
+ }
47
+ /** The RFC 7591 fields a registration request may carry. */
48
+ export interface ClientMetadataInput {
49
+ client_name?: unknown;
50
+ client_uri?: unknown;
51
+ logo_uri?: unknown;
52
+ contacts?: unknown;
53
+ software_id?: unknown;
54
+ software_version?: unknown;
55
+ policy_uri?: unknown;
56
+ tos_uri?: unknown;
57
+ redirect_uris?: unknown;
58
+ grant_types?: unknown;
59
+ response_types?: unknown;
60
+ scope?: unknown;
61
+ token_endpoint_auth_method?: unknown;
62
+ [key: string]: unknown;
63
+ }
64
+ /** What an operator hands `registerStaticClient`. Typed, because it is code. */
65
+ export interface StaticClientInput {
66
+ /** The `client_id` the operator wants this client to present. */
67
+ clientId: string;
68
+ name: string;
69
+ redirectUris: string[];
70
+ description?: string;
71
+ logoUri?: string;
72
+ clientUri?: string;
73
+ contacts?: string[];
74
+ policyUri?: string;
75
+ tosUri?: string;
76
+ softwareId?: string;
77
+ softwareVersion?: string;
78
+ grantTypes?: string[];
79
+ responseTypes?: string[];
80
+ scopes?: string[];
81
+ }
82
+ /**
83
+ * A Client ID Metadata Document, as fetched.
84
+ *
85
+ * Every field is `unknown` on arrival: the document is written by whoever owns
86
+ * the URL, which is to say by someone who is not us.
87
+ */
88
+ export interface ClientIdMetadataDocument {
89
+ client_id?: unknown;
90
+ client_name?: unknown;
91
+ client_uri?: unknown;
92
+ logo_uri?: unknown;
93
+ contacts?: unknown;
94
+ policy_uri?: unknown;
95
+ tos_uri?: unknown;
96
+ redirect_uris?: unknown;
97
+ grant_types?: unknown;
98
+ response_types?: unknown;
99
+ scope?: unknown;
100
+ token_endpoint_auth_method?: unknown;
101
+ [key: string]: unknown;
102
+ }
103
+ /**
104
+ * The slice of Prisma's `oauthClient` delegate this capability uses.
105
+ *
106
+ * Declared structurally rather than imported from `@prisma/client`, for the
107
+ * same reason cap-users declares its own: the package must build without a
108
+ * generated client, and the identity-boundary audit reads the import list.
109
+ */
110
+ export interface OauthClientDelegate {
111
+ create(args: {
112
+ data: Record<string, unknown>;
113
+ }): Promise<Record<string, unknown>>;
114
+ findUnique(args: {
115
+ where: Record<string, unknown>;
116
+ }): Promise<Record<string, unknown> | null>;
117
+ findFirst(args: {
118
+ where: Record<string, unknown>;
119
+ }): Promise<Record<string, unknown> | null>;
120
+ findMany(args?: Record<string, unknown>): Promise<Record<string, unknown>[]>;
121
+ update(args: {
122
+ where: Record<string, unknown>;
123
+ data: Record<string, unknown>;
124
+ }): Promise<Record<string, unknown>>;
125
+ delete(args: {
126
+ where: Record<string, unknown>;
127
+ }): Promise<Record<string, unknown>>;
128
+ count(args?: Record<string, unknown>): Promise<number>;
129
+ }
130
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * The client registry's vocabulary.
4
+ *
5
+ * Everything here describes a piece of *software* that asks to act on a user's
6
+ * behalf. Nothing here describes a user or an account — those live in cap-users
7
+ * and are reached only through its public surface. Keeping the two vocabularies
8
+ * apart is what stops OAuth from becoming a parallel identity system.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.CLIENT_MODES = void 0;
12
+ exports.CLIENT_MODES = ['dynamic', 'metadata_document', 'static'];
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAQU,QAAA,YAAY,GAA0B,CAAC,SAAS,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The two cap-users services this capability calls, declared structurally.
3
+ *
4
+ * ## Why these are interfaces here rather than imports
5
+ *
6
+ * The identity boundary says every user-, account- or identity-shaped read goes
7
+ * through cap-users' public surface. It does *not* say this package should link
8
+ * against cap-users' concrete service types — and for the property service it
9
+ * says the opposite. The import audit
10
+ * (`tests/packages/cap-oauth-server-import-audit.test.ts`) forbids importing
11
+ * `UserPropertyService` from cap-users by name, because that surface can read
12
+ * cap-users' own `authentication` and `profile` properties, and a capability
13
+ * that reads those with a schema of its own has created a second definition of
14
+ * the user.
15
+ *
16
+ * So the ports below name **exactly the calls this capability makes, on exactly
17
+ * the two properties it owns** — `oauth-grants` and `oauth-codes` — and the
18
+ * application's real `identityService` and `userPropertyService` are injected
19
+ * into them by the scaffold binding. cap-users stays the only implementation;
20
+ * what narrows is what this package is able to ask for.
21
+ *
22
+ * The same reasoning produced `OauthClientDelegate` in `types.ts`, and it is
23
+ * the reasoning cap-users itself uses for its own Prisma delegates.
24
+ */
25
+ /** A `user_identities` row, as cap-users' identity service returns it. */
26
+ export interface StoredIdentity {
27
+ id: number;
28
+ userId: number;
29
+ domain: string;
30
+ key: string;
31
+ /** The tombstone. Never a scheduled expiry — see `token-service.ts`. */
32
+ endedAt: Date | null;
33
+ createdAt: Date;
34
+ updatedAt: Date;
35
+ }
36
+ /** One page of cap-users' key-prefix scan. */
37
+ export interface StoredIdentityPage {
38
+ identities: StoredIdentity[];
39
+ /** Pass back as `after`. `null` when the scan is finished. */
40
+ nextCursor: number | null;
41
+ }
42
+ /** The slice of cap-users' `IdentityService` the OAuth token paths call. */
43
+ export interface IdentityStore {
44
+ create(userId: number, domain: string, key: string): Promise<StoredIdentity>;
45
+ /** Active-only: a row with `endedAt` set reads as absent. */
46
+ findByDomainAndKey(domain: string, key: string): Promise<StoredIdentity | null>;
47
+ findAllByUser(userId: number, opts?: {
48
+ includeEnded?: boolean;
49
+ }): Promise<StoredIdentity[]>;
50
+ /**
51
+ * One page of the rows in `domain` whose key starts with `keyPrefix`, for any
52
+ * user — cap-users' `findAllByDomainAndKeyPrefix`.
53
+ *
54
+ * The only read on this port that is not bounded by a user id, and the only
55
+ * one client-wide revocation could not be built without: a token key is
56
+ * `"<publicId>|<hash>"`, so everybody one client ever reached is a
57
+ * left-anchored prefix away. It stays cap-users' query rather than becoming
58
+ * ours — the identity boundary is the same whether the read is by id or by
59
+ * prefix.
60
+ */
61
+ findAllByDomainAndKeyPrefix(domain: string, keyPrefix: string, opts?: {
62
+ includeEnded?: boolean;
63
+ limit?: number;
64
+ after?: number;
65
+ }): Promise<StoredIdentityPage>;
66
+ endDate(domain: string, key: string): Promise<StoredIdentity>;
67
+ }
68
+ /** A `user_properties` row, as cap-users' property service returns it. */
69
+ export interface StoredProperty<T = unknown> {
70
+ id: number;
71
+ property: string;
72
+ info: T;
73
+ infoSchema: string;
74
+ /** Bumped on every write. The token in the read-modify-write discipline. */
75
+ revision: number;
76
+ createdAt: Date;
77
+ updatedAt: Date;
78
+ }
79
+ export interface PropertyWriteOptions {
80
+ infoSchema?: string;
81
+ /**
82
+ * The revision the caller read. The write is refused if the stored row has
83
+ * moved on — which is the whole reason `oauth-grants` and `oauth-codes` are
84
+ * user properties rather than columns.
85
+ */
86
+ expectedRevision?: number;
87
+ }
88
+ /**
89
+ * The slice of cap-users' user-property service the grant and code services
90
+ * call — and deliberately only `get` and `put`.
91
+ *
92
+ * `patch` is absent by design. It shallow-merges, and every value this
93
+ * capability stores is an **array**; merging two arrays by key index is how
94
+ * boop-zj8 destroyed fields a write never named. Every write here replaces the
95
+ * whole array under `expectedRevision`, following cap-users' `setAuthorization`
96
+ * and never its `addAuthenticationMethod`.
97
+ */
98
+ export interface PropertyStore {
99
+ get<T = unknown>(userId: number, property: string): Promise<StoredProperty<T> | null>;
100
+ put<T = unknown>(userId: number, property: string, info: T, opts?: PropertyWriteOptions): Promise<StoredProperty<T>>;
101
+ }
102
+ /**
103
+ * Was this write refused because somebody else got there first?
104
+ *
105
+ * cap-services throws `StaleEntityError`; matched by `name` rather than by
106
+ * `instanceof` because the class is not on this package's import allowlist and
107
+ * because `instanceof` across two copies of a module is a false negative.
108
+ */
109
+ export declare function isStaleWriteError(err: unknown): boolean;
110
+ //# sourceMappingURL=user-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-store.d.ts","sourceRoot":"","sources":["../src/user-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,8DAA8D;IAC9D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7E,6DAA6D;IAC7D,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChF,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC5F;;;;;;;;;;OAUG;IACH,2BAA2B,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC/D;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,CAAC,CAAC;IACR,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACtF,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE,oBAAoB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAMvD"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * The two cap-users services this capability calls, declared structurally.
4
+ *
5
+ * ## Why these are interfaces here rather than imports
6
+ *
7
+ * The identity boundary says every user-, account- or identity-shaped read goes
8
+ * through cap-users' public surface. It does *not* say this package should link
9
+ * against cap-users' concrete service types — and for the property service it
10
+ * says the opposite. The import audit
11
+ * (`tests/packages/cap-oauth-server-import-audit.test.ts`) forbids importing
12
+ * `UserPropertyService` from cap-users by name, because that surface can read
13
+ * cap-users' own `authentication` and `profile` properties, and a capability
14
+ * that reads those with a schema of its own has created a second definition of
15
+ * the user.
16
+ *
17
+ * So the ports below name **exactly the calls this capability makes, on exactly
18
+ * the two properties it owns** — `oauth-grants` and `oauth-codes` — and the
19
+ * application's real `identityService` and `userPropertyService` are injected
20
+ * into them by the scaffold binding. cap-users stays the only implementation;
21
+ * what narrows is what this package is able to ask for.
22
+ *
23
+ * The same reasoning produced `OauthClientDelegate` in `types.ts`, and it is
24
+ * the reasoning cap-users itself uses for its own Prisma delegates.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.isStaleWriteError = isStaleWriteError;
28
+ /**
29
+ * Was this write refused because somebody else got there first?
30
+ *
31
+ * cap-services throws `StaleEntityError`; matched by `name` rather than by
32
+ * `instanceof` because the class is not on this package's import allowlist and
33
+ * because `instanceof` across two copies of a module is a false negative.
34
+ */
35
+ function isStaleWriteError(err) {
36
+ return (typeof err === 'object' &&
37
+ err !== null &&
38
+ err.name === 'StaleEntityError');
39
+ }
40
+ //# sourceMappingURL=user-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-store.js","sourceRoot":"","sources":["../src/user-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;AA+FH,8CAMC;AAbD;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,GAAY;IAC5C,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACX,GAA0B,CAAC,IAAI,KAAK,kBAAkB,CACxD,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@boopkit/cap-oauth-server",
3
+ "version": "0.1.0",
4
+ "description": "Make a boop app an OAuth 2.1 authorization server and resource server, so an MCP client can act on behalf of one of its users",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/",
9
+ "scaffold/",
10
+ "skills/",
11
+ "capability.json"
12
+ ],
13
+ "boopkit": {
14
+ "capability": true,
15
+ "scaffoldDir": "scaffold",
16
+ "skillsDir": "skills",
17
+ "manifest": "capability.json"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json"
21
+ },
22
+ "dependencies": {
23
+ "@boopkit/cap-users": "^0.8.0",
24
+ "@boopkit/logger": "^0.4.0"
25
+ },
26
+ "peerDependencies": {
27
+ "express": ">=4.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/express": "^5.0.0",
31
+ "typescript": "^5.9.3"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "license": "ISC"
37
+ }
@@ -0,0 +1,80 @@
1
+ // @boopkit/cap-oauth-server — OAuth client registry
2
+ // Scaffolded by boop. Modify freely — this file is developer-owned.
3
+ //
4
+ // One table with a `mode` discriminator, not three tables. The three
5
+ // registration modes — open dynamic registration (RFC 7591), a Client ID
6
+ // Metadata Document, and an operator-configured static client — differ in
7
+ // almost nothing except which column is authoritative for `redirectUris` (the
8
+ // local JSON array, or the document at `metadataUri`) and what the consent page
9
+ // says about provenance.
10
+ //
11
+ // This is the capability's own table. It holds nothing user- or account-shaped:
12
+ // a client is a piece of software, not a person, and the grant that ties a
13
+ // client to a user lives in cap-users' `user_properties` under `oauth-grants`.
14
+
15
+ model OauthClient {
16
+ id Int @id @default(autoincrement())
17
+
18
+ // The token prefix, assigned by us at registration in *every* mode.
19
+ // Twelve lowercase base36 characters: no `.`, `|`, `/` or `:`, so
20
+ // `<publicId>.<token>` and `<publicId>|<sha256>` both split unambiguously.
21
+ // varchar(16) rather than (12) so a future format change does not need a
22
+ // migration to widen the column.
23
+ publicId String @unique @map("public_id") @db.VarChar(16)
24
+
25
+ // What the client sends as `client_id`. Equals `publicId` for `dynamic` and
26
+ // `static`; is the metadata-document URL for `metadata_document`, which is
27
+ // why this column is wide and `publicId` is not.
28
+ clientId String @unique @map("client_id") @db.VarChar(512)
29
+
30
+ // `dynamic` | `metadata_document` | `static`. Reaches the consent view, which
31
+ // says something different about a client whose metadata we hold than about
32
+ // one whose metadata lives at a URL the client controls.
33
+ mode String @db.VarChar(32)
34
+
35
+ // `enabled` | `suspended`. Suspending a compromised client must not delete a
36
+ // row that live tokens still carry the prefix of.
37
+ status String @default("enabled") @db.VarChar(32)
38
+
39
+ // The display fields the consent screen cannot render without.
40
+ name String? @db.VarChar(255)
41
+ description String?
42
+ logoUri String? @map("logo_uri") @db.VarChar(2048)
43
+
44
+ // RFC 7591 metadata, echoed on the registration response.
45
+ clientUri String? @map("client_uri") @db.VarChar(2048)
46
+ contacts Json?
47
+ softwareId String? @map("software_id") @db.VarChar(255)
48
+ softwareVersion String? @map("software_version") @db.VarChar(255)
49
+ policyUri String? @map("policy_uri") @db.VarChar(2048)
50
+ tosUri String? @map("tos_uri") @db.VarChar(2048)
51
+
52
+ // Authoritative for `dynamic` and `static`; a *cache* for
53
+ // `metadata_document`, refreshed from `metadataUri`.
54
+ redirectUris Json @map("redirect_uris")
55
+
56
+ // What this client may request.
57
+ grantTypes Json @map("grant_types")
58
+ responseTypes Json @map("response_types")
59
+ scopes Json
60
+
61
+ // `none` is the only value v1 supports — every Claude-ecosystem client is a
62
+ // public client, and a public client that sent a secret would be sending one
63
+ // it shipped to its users.
64
+ tokenEndpointAuthMethod String @default("none") @map("token_endpoint_auth_method") @db.VarChar(64)
65
+
66
+ // Client ID Metadata Document only. `metadataUri` equals `clientId`, but is
67
+ // kept as its own column so the fetch target is explicit rather than inferred
68
+ // from a mode check at every call site.
69
+ metadataUri String? @map("metadata_uri") @db.VarChar(512)
70
+ metadataFetchedAt DateTime? @map("metadata_fetched_at") @db.Timestamptz(6)
71
+
72
+ createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
73
+ updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6)
74
+
75
+ // Garbage collection walks `dynamic` rows by age; suspension checks read
76
+ // `status` on the token path.
77
+ @@index([mode, createdAt])
78
+ @@index([status])
79
+ @@map("oauth_clients")
80
+ }