@n24q02m/hull 0.4.0-beta.9 → 0.5.0-beta.1

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 (169) hide show
  1. package/README.md +47 -16
  2. package/build/cli/build-cli.d.ts +5 -6
  3. package/build/cli/build-cli.d.ts.map +1 -1
  4. package/build/cli/build-cli.js +4 -61
  5. package/build/cli/build-cli.js.map +1 -1
  6. package/build/crypto/index.d.ts +1 -1
  7. package/build/crypto/index.d.ts.map +1 -1
  8. package/build/crypto/index.js +1 -1
  9. package/build/crypto/index.js.map +1 -1
  10. package/build/crypto/kdf.d.ts +0 -13
  11. package/build/crypto/kdf.d.ts.map +1 -1
  12. package/build/crypto/kdf.js +3 -18
  13. package/build/crypto/kdf.js.map +1 -1
  14. package/build/index.d.ts +1 -11
  15. package/build/index.d.ts.map +1 -1
  16. package/build/index.js +4 -16
  17. package/build/index.js.map +1 -1
  18. package/build/storage/account-registry.d.ts +53 -0
  19. package/build/storage/account-registry.d.ts.map +1 -0
  20. package/build/storage/account-registry.js +148 -0
  21. package/build/storage/account-registry.js.map +1 -0
  22. package/build/storage/backends.d.ts +0 -26
  23. package/build/storage/backends.d.ts.map +1 -1
  24. package/build/storage/backends.js +0 -65
  25. package/build/storage/backends.js.map +1 -1
  26. package/build/storage/config-file.d.ts +2 -19
  27. package/build/storage/config-file.d.ts.map +1 -1
  28. package/build/storage/config-file.js +2 -23
  29. package/build/storage/config-file.js.map +1 -1
  30. package/build/storage/credential-store.d.ts +1 -9
  31. package/build/storage/credential-store.d.ts.map +1 -1
  32. package/build/storage/credential-store.js +4 -16
  33. package/build/storage/credential-store.js.map +1 -1
  34. package/build/storage/data-dir.d.ts +2 -2
  35. package/build/storage/data-dir.js +2 -2
  36. package/build/storage/encryption.d.ts.map +1 -1
  37. package/build/storage/encryption.js +4 -0
  38. package/build/storage/encryption.js.map +1 -1
  39. package/build/storage/index.d.ts +5 -3
  40. package/build/storage/index.d.ts.map +1 -1
  41. package/build/storage/index.js +5 -3
  42. package/build/storage/index.js.map +1 -1
  43. package/build/storage/key-pool-crypto.d.ts +44 -0
  44. package/build/storage/key-pool-crypto.d.ts.map +1 -0
  45. package/build/storage/key-pool-crypto.js +132 -0
  46. package/build/storage/key-pool-crypto.js.map +1 -0
  47. package/build/storage/key-pool-store.d.ts +134 -0
  48. package/build/storage/key-pool-store.d.ts.map +1 -0
  49. package/build/storage/key-pool-store.js +470 -0
  50. package/build/storage/key-pool-store.js.map +1 -0
  51. package/build/storage/key-pool.d.ts +172 -0
  52. package/build/storage/key-pool.d.ts.map +1 -0
  53. package/build/storage/key-pool.js +374 -0
  54. package/build/storage/key-pool.js.map +1 -0
  55. package/build/storage/resolver.js +1 -1
  56. package/build/storage/resolver.js.map +1 -1
  57. package/build/token-auth/index.d.ts +1 -1
  58. package/build/token-auth/index.js +1 -1
  59. package/build/transport/index.d.ts +1 -2
  60. package/build/transport/index.d.ts.map +1 -1
  61. package/build/transport/index.js +1 -2
  62. package/build/transport/index.js.map +1 -1
  63. package/build/transport/local-server.d.ts +12 -128
  64. package/build/transport/local-server.d.ts.map +1 -1
  65. package/build/transport/local-server.js +20 -262
  66. package/build/transport/local-server.js.map +1 -1
  67. package/build/transport/streamable-http.d.ts +6 -7
  68. package/build/transport/streamable-http.d.ts.map +1 -1
  69. package/build/transport/streamable-http.js +6 -6
  70. package/build/transport/streamable-http.js.map +1 -1
  71. package/build/util/browser.d.ts.map +1 -0
  72. package/build/{relay → util}/browser.js +2 -2
  73. package/build/util/browser.js.map +1 -0
  74. package/package.json +4 -21
  75. package/build/auth/credential-form.d.ts +0 -163
  76. package/build/auth/credential-form.d.ts.map +0 -1
  77. package/build/auth/credential-form.js +0 -1869
  78. package/build/auth/credential-form.js.map +0 -1
  79. package/build/auth/delegated-oauth-app.d.ts +0 -90
  80. package/build/auth/delegated-oauth-app.d.ts.map +0 -1
  81. package/build/auth/delegated-oauth-app.js +0 -881
  82. package/build/auth/delegated-oauth-app.js.map +0 -1
  83. package/build/auth/index.d.ts +0 -12
  84. package/build/auth/index.d.ts.map +0 -1
  85. package/build/auth/index.js +0 -12
  86. package/build/auth/index.js.map +0 -1
  87. package/build/auth/local-oauth-app.d.ts +0 -152
  88. package/build/auth/local-oauth-app.d.ts.map +0 -1
  89. package/build/auth/local-oauth-app.js +0 -975
  90. package/build/auth/local-oauth-app.js.map +0 -1
  91. package/build/auth/relay-login.d.ts +0 -46
  92. package/build/auth/relay-login.d.ts.map +0 -1
  93. package/build/auth/relay-login.js +0 -197
  94. package/build/auth/relay-login.js.map +0 -1
  95. package/build/auth/router.d.ts +0 -18
  96. package/build/auth/router.d.ts.map +0 -1
  97. package/build/auth/router.js +0 -62
  98. package/build/auth/router.js.map +0 -1
  99. package/build/auth/session-store.d.ts +0 -49
  100. package/build/auth/session-store.d.ts.map +0 -1
  101. package/build/auth/session-store.js +0 -94
  102. package/build/auth/session-store.js.map +0 -1
  103. package/build/auth/stable-sub.d.ts +0 -27
  104. package/build/auth/stable-sub.d.ts.map +0 -1
  105. package/build/auth/stable-sub.js +0 -38
  106. package/build/auth/stable-sub.js.map +0 -1
  107. package/build/auth/well-known.d.ts +0 -4
  108. package/build/auth/well-known.d.ts.map +0 -1
  109. package/build/auth/well-known.js +0 -26
  110. package/build/auth/well-known.js.map +0 -1
  111. package/build/oauth/cache.d.ts +0 -22
  112. package/build/oauth/cache.d.ts.map +0 -1
  113. package/build/oauth/cache.js +0 -24
  114. package/build/oauth/cache.js.map +0 -1
  115. package/build/oauth/index.d.ts +0 -6
  116. package/build/oauth/index.d.ts.map +0 -1
  117. package/build/oauth/index.js +0 -6
  118. package/build/oauth/index.js.map +0 -1
  119. package/build/oauth/jwt-issuer.d.ts +0 -87
  120. package/build/oauth/jwt-issuer.d.ts.map +0 -1
  121. package/build/oauth/jwt-issuer.js +0 -205
  122. package/build/oauth/jwt-issuer.js.map +0 -1
  123. package/build/oauth/pkce.d.ts +0 -10
  124. package/build/oauth/pkce.d.ts.map +0 -1
  125. package/build/oauth/pkce.js +0 -34
  126. package/build/oauth/pkce.js.map +0 -1
  127. package/build/oauth/provider.d.ts +0 -52
  128. package/build/oauth/provider.d.ts.map +0 -1
  129. package/build/oauth/provider.js +0 -98
  130. package/build/oauth/provider.js.map +0 -1
  131. package/build/oauth/user-store.d.ts +0 -25
  132. package/build/oauth/user-store.d.ts.map +0 -1
  133. package/build/oauth/user-store.js +0 -85
  134. package/build/oauth/user-store.js.map +0 -1
  135. package/build/relay/browser.d.ts.map +0 -1
  136. package/build/relay/browser.js.map +0 -1
  137. package/build/relay/client.d.ts +0 -36
  138. package/build/relay/client.d.ts.map +0 -1
  139. package/build/relay/client.js +0 -135
  140. package/build/relay/client.js.map +0 -1
  141. package/build/relay/session.d.ts +0 -12
  142. package/build/relay/session.d.ts.map +0 -1
  143. package/build/relay/session.js +0 -55
  144. package/build/relay/session.js.map +0 -1
  145. package/build/relay/tool-helpers.d.ts +0 -85
  146. package/build/relay/tool-helpers.d.ts.map +0 -1
  147. package/build/relay/tool-helpers.js +0 -103
  148. package/build/relay/tool-helpers.js.map +0 -1
  149. package/build/relay/wordlist.d.ts +0 -2
  150. package/build/relay/wordlist.d.ts.map +0 -1
  151. package/build/relay/wordlist.js +0 -7782
  152. package/build/relay/wordlist.js.map +0 -1
  153. package/build/schema/types.d.ts +0 -67
  154. package/build/schema/types.d.ts.map +0 -1
  155. package/build/schema/types.js +0 -2
  156. package/build/schema/types.js.map +0 -1
  157. package/build/storage/mode.d.ts +0 -23
  158. package/build/storage/mode.d.ts.map +0 -1
  159. package/build/storage/mode.js +0 -46
  160. package/build/storage/mode.js.map +0 -1
  161. package/build/storage/session-lock.d.ts +0 -19
  162. package/build/storage/session-lock.d.ts.map +0 -1
  163. package/build/storage/session-lock.js +0 -105
  164. package/build/storage/session-lock.js.map +0 -1
  165. package/build/transport/oauth-middleware.d.ts +0 -45
  166. package/build/transport/oauth-middleware.d.ts.map +0 -1
  167. package/build/transport/oauth-middleware.js +0 -86
  168. package/build/transport/oauth-middleware.js.map +0 -1
  169. /package/build/{relay → util}/browser.d.ts +0 -0
@@ -1,38 +0,0 @@
1
- /**
2
- * Derive a stable, opaque subject id from a workspace username.
3
- *
4
- * TypeScript port of core-py's ``stable_sub.py``. Output is byte-identical for
5
- * ASCII usernames, locked by the shared ``crypto-vectors.json`` fixture.
6
- */
7
- import { createHmac } from 'node:crypto';
8
- // Used only when CREDENTIAL_SECRET is unset (single-user/dev): the sub stays
9
- // stable, just predictable. Production multi-user always sets CREDENTIAL_SECRET.
10
- const DEV_FALLBACK_KEY = Buffer.from('mcp-core-stable-sub-dev-salt', 'utf-8');
11
- /**
12
- * Derive a stable, opaque subject id from a workspace username.
13
- *
14
- * Same ``(serverName, normalized username)`` -> same ``sub``, so a returning
15
- * user lands on the same per-``sub`` credential bucket instead of the random
16
- * subject minted per ``/authorize``. The output shape (22 chars, urlsafe
17
- * base64, no padding) matches ``randomBytes(16).toString('base64url')`` so
18
- * downstream code cannot tell a stable sub from a random one.
19
- *
20
- * Normalization is ``trim().toLowerCase()``. Python's ``str.casefold()`` maps
21
- * a few non-ASCII characters differently (``'ß'.casefold() == 'ss'``), so
22
- * cross-language parity is guaranteed for ASCII usernames only; the divergence
23
- * is asserted by a test in both languages.
24
- *
25
- * SECURITY: with a SHARED relay password the username is a PARTITION key, NOT a
26
- * secret -- anyone who knows the password can submit any username and reach that
27
- * bucket. Intentional for a trusted group; untrusted multi-tenant needs per-user
28
- * secrets or delegated OAuth.
29
- */
30
- export function deriveStableSub(username, serverName, credentialSecret) {
31
- const normalized = username.trim().toLowerCase();
32
- if (!normalized)
33
- throw new Error('username must be non-empty');
34
- const key = credentialSecret ? Buffer.from(credentialSecret, 'utf-8') : DEV_FALLBACK_KEY;
35
- const digest = createHmac('sha256', key).update(`sub:${serverName}:${normalized}`, 'utf8').digest();
36
- return digest.subarray(0, 16).toString('base64url');
37
- }
38
- //# sourceMappingURL=stable-sub.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stable-sub.js","sourceRoot":"","sources":["../../src/auth/stable-sub.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,6EAA6E;AAC7E,iFAAiF;AACjF,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,OAAO,CAAC,CAAA;AAE7E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,UAAkB,EAClB,gBAA2C;IAE3C,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAChD,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC9D,MAAM,GAAG,GAAG,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAA;IACxF,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,UAAU,IAAI,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAA;IACnG,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AACrD,CAAC"}
@@ -1,4 +0,0 @@
1
- /** OAuth 2.1 well-known metadata generators (RFC 8414 + RFC 9728). */
2
- export declare function authorizationServerMetadata(issuerUrl: string): Record<string, unknown>;
3
- export declare function protectedResourceMetadata(resource: string, authorizationServers: string[]): Record<string, unknown>;
4
- //# sourceMappingURL=well-known.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"well-known.d.ts","sourceRoot":"","sources":["../../src/auth/well-known.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBtF;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMnH"}
@@ -1,26 +0,0 @@
1
- /** OAuth 2.1 well-known metadata generators (RFC 8414 + RFC 9728). */
2
- export function authorizationServerMetadata(issuerUrl) {
3
- return {
4
- issuer: issuerUrl,
5
- authorization_endpoint: `${issuerUrl}/authorize`,
6
- token_endpoint: `${issuerUrl}/token`,
7
- registration_endpoint: `${issuerUrl}/register`,
8
- jwks_uri: `${issuerUrl}/.well-known/jwks.json`,
9
- response_types_supported: ['code'],
10
- grant_types_supported: ['authorization_code', 'refresh_token'],
11
- code_challenge_methods_supported: ['S256'],
12
- token_endpoint_auth_methods_supported: ['none'],
13
- scopes_supported: ['offline_access'],
14
- // RFC 9207 / SEP-2468: the AS returns the ``iss`` parameter in every
15
- // authorization response so clients can defend against mix-up attacks.
16
- authorization_response_iss_parameter_supported: true
17
- };
18
- }
19
- export function protectedResourceMetadata(resource, authorizationServers) {
20
- return {
21
- resource,
22
- authorization_servers: authorizationServers,
23
- bearer_methods_supported: ['header']
24
- };
25
- }
26
- //# sourceMappingURL=well-known.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"well-known.js","sourceRoot":"","sources":["../../src/auth/well-known.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,MAAM,UAAU,2BAA2B,CAAC,SAAiB;IAC3D,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,sBAAsB,EAAE,GAAG,SAAS,YAAY;QAChD,cAAc,EAAE,GAAG,SAAS,QAAQ;QACpC,qBAAqB,EAAE,GAAG,SAAS,WAAW;QAC9C,QAAQ,EAAE,GAAG,SAAS,wBAAwB;QAC9C,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC9D,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,qCAAqC,EAAE,CAAC,MAAM,CAAC;QAC/C,gBAAgB,EAAE,CAAC,gBAAgB,CAAC;QACpC,qEAAqE;QACrE,uEAAuE;QACvE,8CAA8C,EAAE,IAAI;KACrD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAgB,EAAE,oBAA8B;IACxF,OAAO;QACL,QAAQ;QACR,qBAAqB,EAAE,oBAAoB;QAC3C,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,CAAA;AACH,CAAC"}
@@ -1,22 +0,0 @@
1
- export interface PreAuthSession {
2
- sessionId: string;
3
- clientId: string;
4
- redirectUri: string;
5
- state: string;
6
- codeChallenge: string;
7
- codeChallengeMethod: string;
8
- /** Serialized CryptoKeyPair for later credential retrieval */
9
- keyPairJwk: JsonWebKey;
10
- passphrase: string;
11
- expiresAt: number;
12
- }
13
- export interface IOAuthSessionCache {
14
- save(session: PreAuthSession): void;
15
- getAndDelete(sessionId: string): PreAuthSession | null;
16
- }
17
- export declare class InMemoryAuthCache implements IOAuthSessionCache {
18
- private cache;
19
- save(session: PreAuthSession): void;
20
- getAndDelete(sessionId: string): PreAuthSession | null;
21
- }
22
- //# sourceMappingURL=cache.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/oauth/cache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,8DAA8D;IAC9D,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAA;CACvD;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,KAAK,CAAoC;IAEjD,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAOlC;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMrD;CACF"}
@@ -1,24 +0,0 @@
1
- export class InMemoryAuthCache {
2
- constructor() {
3
- this.cache = new Map();
4
- }
5
- save(session) {
6
- this.cache.set(session.sessionId, session);
7
- // Cleanup expired entries
8
- const now = Math.floor(Date.now() / 1000);
9
- for (const [id, sess] of this.cache) {
10
- if (sess.expiresAt < now)
11
- this.cache.delete(id);
12
- }
13
- }
14
- getAndDelete(sessionId) {
15
- const sess = this.cache.get(sessionId);
16
- if (!sess)
17
- return null;
18
- this.cache.delete(sessionId);
19
- if (sess.expiresAt < Math.floor(Date.now() / 1000))
20
- return null;
21
- return sess;
22
- }
23
- }
24
- //# sourceMappingURL=cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/oauth/cache.ts"],"names":[],"mappings":"AAkBA,MAAM,OAAO,iBAAiB;IAA9B;QACU,UAAK,GAAG,IAAI,GAAG,EAA0B,CAAA;IAkBnD,CAAC;IAhBC,IAAI,CAAC,OAAuB;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAC1C,0BAA0B;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACzC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,SAAS,GAAG,GAAG;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACjD,CAAC;IACH,CAAC;IAED,YAAY,CAAC,SAAiB;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC5B,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAC/D,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
@@ -1,6 +0,0 @@
1
- export { InMemoryAuthCache, type IOAuthSessionCache, type PreAuthSession } from './cache.js';
2
- export { JWTIssuer } from './jwt-issuer.js';
3
- export { verifyPKCE } from './pkce.js';
4
- export { OAuthProvider, type OAuthProviderOptions } from './provider.js';
5
- export { type IUserCredentialStore, SqliteUserStore } from './user-store.js';
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -1,6 +0,0 @@
1
- export { InMemoryAuthCache } from './cache.js';
2
- export { JWTIssuer } from './jwt-issuer.js';
3
- export { verifyPKCE } from './pkce.js';
4
- export { OAuthProvider } from './provider.js';
5
- export { SqliteUserStore } from './user-store.js';
6
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAGlB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACL,aAAa,EAEd,MAAM,eAAe,CAAA;AACtB,OAAO,EAA6B,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -1,87 +0,0 @@
1
- /**
2
- * JWT Issuer and JWKS generation for TypeScript MCP servers.
3
- * Uses jose (industry-standard, zero-dep, Web Crypto compatible).
4
- *
5
- * Two signing modes, selected at construction:
6
- *
7
- * - LOCAL single-user (credentialSecret unset): RSA-2048, RS256, kid="key-1",
8
- * keys generated on first run and persisted to disk so they survive restarts
9
- * on a real machine. Behavior is unchanged from the pre-stability-fix code.
10
- *
11
- * - HTTP multi-user (credentialSecret set): Ed25519, EdDSA, signing key DERIVED
12
- * deterministically from CREDENTIAL_SECRET via HKDF-SHA256. No disk I/O. Every
13
- * container replica converges on the same key without a shared volume or
14
- * external secret store, so OAuth tokens survive container recreation
15
- * (Watchtower :latest redeploys). kid is the base64url SHA-256 thumbprint of
16
- * the raw public key.
17
- *
18
- * The two modes are different deployments that never exchange tokens
19
- * (iss/aud are server-scoped); the per-mode algorithm split is permanent and
20
- * intentional. Each process runs exactly one algorithm; the verify path uses
21
- * that single alg, never a {RS256, EdDSA} union.
22
- */
23
- import * as jose from 'jose';
24
- export declare class JWTIssuer {
25
- private serverName;
26
- private keysDir;
27
- private privateKeyPath;
28
- private publicKeyPath;
29
- private credentialSecret;
30
- alg: 'RS256' | 'EdDSA';
31
- private kid;
32
- private privateKey;
33
- private publicKey;
34
- private okpX;
35
- private _initialized;
36
- constructor(serverName: string, keysDir?: string, credentialSecret?: string | null);
37
- /** Must call before using issuer — loads/generates (RSA) or derives (EdDSA) keys. */
38
- init(): Promise<void>;
39
- private deriveEddsaKeys;
40
- private loadOrGenerateRsaKeys;
41
- /**
42
- * Return JWKS payload for /.well-known/jwks.json. Always a `keys` array
43
- * (multi-key-aware for future rotation). RSA mode emits an RSA JWK; EdDSA
44
- * mode emits an OKP JWK.
45
- */
46
- getJwks(): Promise<jose.JSONWebKeySet>;
47
- /** Issue a JWT access token (typ="access") signed with the active alg. */
48
- issueAccessToken(sub: string, expiresInSeconds?: number): Promise<string>;
49
- /**
50
- * Issue a JWT refresh token (typ="refresh") signed with the active alg.
51
- *
52
- * Defaults to a 1-year (31536000s) lifetime so long-running MCP clients can
53
- * mint fresh access tokens without forcing the user back through the browser
54
- * PKCE flow. The access token stays short-lived (1h); the refresh token is the
55
- * renewal credential and is rotated on every use (the /token refresh handler
56
- * issues a new refresh token each time), so the security control is rotation,
57
- * not a short TTL. A short refresh TTL was the residual re-auth driver: a
58
- * self-hosted server a user touches only intermittently (less than once a
59
- * month) would silently expire its refresh token between sessions, forcing a
60
- * fresh browser OAuth tab on the next use. With a 1-year floor, only a
61
- * genuinely long idle gap re-prompts. Same key / iss / aud as access tokens;
62
- * the typ claim is the only thing distinguishing them, and verifyAccessToken
63
- * rejects typ="refresh" so a refresh token can never be used as an access
64
- * token at the /mcp resource.
65
- */
66
- issueRefreshToken(sub: string, expiresInSeconds?: number): Promise<string>;
67
- /**
68
- * Verify a JWT access token and return its payload. Throws on failure (bad
69
- * signature, wrong issuer/audience, expired) — the same jose errors existing
70
- * callers already catch. The verify path uses the single active algorithm,
71
- * never a union. Additionally rejects tokens whose typ claim is "refresh"
72
- * (throwing jose.errors.JWTClaimValidationFailed) so a refresh token cannot
73
- * be replayed as an access token. Tokens with typ="access" OR a missing typ
74
- * claim are accepted (the latter keeps already-issued pre-refresh-support
75
- * tokens valid).
76
- */
77
- verifyAccessToken(token: string): Promise<jose.JWTPayload>;
78
- /**
79
- * Verify a JWT refresh token and return its payload. Same key / audience /
80
- * issuer checks as verifyAccessToken and throws the same jose errors on
81
- * failure; uses the single active algorithm. Additionally asserts
82
- * typ=="refresh" (throwing jose.errors.JWTClaimValidationFailed otherwise) so
83
- * an access token can never be exchanged at the refresh grant.
84
- */
85
- verifyRefreshToken(token: string): Promise<jose.JWTPayload>;
86
- }
87
- //# sourceMappingURL=jwt-issuer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jwt-issuer.d.ts","sourceRoot":"","sources":["../../src/oauth/jwt-issuer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAU5B,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,gBAAgB,CAAe;IACvC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IACtB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,YAAY,CAAQ;IAE5B,YAAY,UAAU,EAAE,MAAM,EAAE,OAAO,SAAmB,EAAE,gBAAgB,GAAE,MAAM,GAAG,IAAW,EAOjG;IAED,qFAAqF;IAC/E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1B;YAEa,eAAe;YAYf,qBAAqB;IA6BnC;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAY3C;IAED,0EAA0E;IACpE,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5E;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,SAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CASjF;IAED;;;;;;;;;OASG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAW/D;IAED;;;;;;OAMG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAWhE;CACF"}
@@ -1,205 +0,0 @@
1
- /**
2
- * JWT Issuer and JWKS generation for TypeScript MCP servers.
3
- * Uses jose (industry-standard, zero-dep, Web Crypto compatible).
4
- *
5
- * Two signing modes, selected at construction:
6
- *
7
- * - LOCAL single-user (credentialSecret unset): RSA-2048, RS256, kid="key-1",
8
- * keys generated on first run and persisted to disk so they survive restarts
9
- * on a real machine. Behavior is unchanged from the pre-stability-fix code.
10
- *
11
- * - HTTP multi-user (credentialSecret set): Ed25519, EdDSA, signing key DERIVED
12
- * deterministically from CREDENTIAL_SECRET via HKDF-SHA256. No disk I/O. Every
13
- * container replica converges on the same key without a shared volume or
14
- * external secret store, so OAuth tokens survive container recreation
15
- * (Watchtower :latest redeploys). kid is the base64url SHA-256 thumbprint of
16
- * the raw public key.
17
- *
18
- * The two modes are different deployments that never exchange tokens
19
- * (iss/aud are server-scoped); the per-mode algorithm split is permanent and
20
- * intentional. Each process runs exactly one algorithm; the verify path uses
21
- * that single alg, never a {RS256, EdDSA} union.
22
- */
23
- import { createHash, createPrivateKey } from 'node:crypto';
24
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
25
- import { homedir } from 'node:os';
26
- import { join } from 'node:path';
27
- import * as jose from 'jose';
28
- import { deriveJwtSigningSeed } from '../crypto/kdf.js';
29
- const DEFAULT_KEYS_DIR = join(homedir(), '.hull', 'jwt-keys');
30
- // RFC 8410 PKCS8 DER prefix for an Ed25519 private key. Prepended to the
31
- // 32-byte HKDF seed to build an importable PKCS8 key (jose 6.2.3 cannot import
32
- // a raw seed via importJWK d-only).
33
- const ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
34
- export class JWTIssuer {
35
- constructor(serverName, keysDir = DEFAULT_KEYS_DIR, credentialSecret = null) {
36
- this.kid = 'key-1';
37
- this.privateKey = null;
38
- this.publicKey = null;
39
- this.okpX = null;
40
- this._initialized = false;
41
- this.serverName = serverName;
42
- this.keysDir = keysDir;
43
- this.credentialSecret = credentialSecret;
44
- this.alg = credentialSecret ? 'EdDSA' : 'RS256';
45
- this.privateKeyPath = join(this.keysDir, `${serverName}_private.pem`);
46
- this.publicKeyPath = join(this.keysDir, `${serverName}_public.pem`);
47
- }
48
- /** Must call before using issuer — loads/generates (RSA) or derives (EdDSA) keys. */
49
- async init() {
50
- if (this._initialized)
51
- return;
52
- if (this.credentialSecret) {
53
- await this.deriveEddsaKeys(this.credentialSecret);
54
- // Don't name the source env var in the message: only serverName + the
55
- // public kid thumbprint are logged (never the secret), and the literal
56
- // "CREDENTIAL_SECRET" token trips the SAST logger-credential heuristic
57
- // for no real benefit (parity with core-py jwt_issuer.py).
58
- console.error(`JWTIssuer[${this.serverName}]: HTTP multi-user mode, EdDSA signing key derived (kid=${this.kid})`);
59
- }
60
- else {
61
- await this.loadOrGenerateRsaKeys();
62
- console.error(`JWTIssuer[${this.serverName}]: local single-user mode, RS256 key on disk (${this.keysDir})`);
63
- }
64
- this._initialized = true;
65
- }
66
- async deriveEddsaKeys(credentialSecret) {
67
- const seed = deriveJwtSigningSeed(credentialSecret, this.serverName);
68
- const der = Buffer.concat([ED25519_PKCS8_PREFIX, seed]);
69
- const pem = `-----BEGIN PRIVATE KEY-----\n${der.toString('base64')}\n-----END PRIVATE KEY-----\n`;
70
- this.privateKey = await jose.importPKCS8(pem, 'EdDSA', { extractable: false });
71
- // Recover the public JWK x via node:crypto (jose has no seed->public path).
72
- const jwk = createPrivateKey(pem).export({ format: 'jwk' });
73
- this.okpX = jwk.x;
74
- this.publicKey = (await jose.importJWK({ kty: 'OKP', crv: 'Ed25519', x: jwk.x }, 'EdDSA'));
75
- this.kid = createHash('sha256').update(Buffer.from(jwk.x, 'base64url')).digest('base64url').slice(0, 16);
76
- }
77
- async loadOrGenerateRsaKeys() {
78
- mkdirSync(this.keysDir, { recursive: true, mode: 0o700 });
79
- if (process.platform !== 'win32') {
80
- chmodSync(this.keysDir, 0o700);
81
- }
82
- if (existsSync(this.privateKeyPath) && existsSync(this.publicKeyPath)) {
83
- const privatePem = readFileSync(this.privateKeyPath, 'utf-8');
84
- const publicPem = readFileSync(this.publicKeyPath, 'utf-8');
85
- this.privateKey = await jose.importPKCS8(privatePem, 'RS256', { extractable: false });
86
- this.publicKey = await jose.importSPKI(publicPem, 'RS256', { extractable: true });
87
- }
88
- else {
89
- const { publicKey, privateKey } = await jose.generateKeyPair('RS256', {
90
- modulusLength: 2048,
91
- extractable: true
92
- });
93
- const privatePem = await jose.exportPKCS8(privateKey);
94
- const publicPem = await jose.exportSPKI(publicKey);
95
- writeFileSync(this.privateKeyPath, privatePem, { mode: 0o600 });
96
- writeFileSync(this.publicKeyPath, publicPem, { mode: 0o644 });
97
- // Re-import with extractable: false for in-memory storage
98
- this.privateKey = await jose.importPKCS8(privatePem, 'RS256', { extractable: false });
99
- this.publicKey = await jose.importSPKI(publicPem, 'RS256', { extractable: true });
100
- }
101
- }
102
- /**
103
- * Return JWKS payload for /.well-known/jwks.json. Always a `keys` array
104
- * (multi-key-aware for future rotation). RSA mode emits an RSA JWK; EdDSA
105
- * mode emits an OKP JWK.
106
- */
107
- async getJwks() {
108
- if (!this.publicKey)
109
- throw new Error('JWTIssuer not initialized');
110
- if (this.alg === 'EdDSA') {
111
- return {
112
- keys: [{ kty: 'OKP', crv: 'Ed25519', x: this.okpX, use: 'sig', alg: 'EdDSA', kid: this.kid }]
113
- };
114
- }
115
- const jwk = await jose.exportJWK(this.publicKey);
116
- jwk.kid = this.kid;
117
- jwk.use = 'sig';
118
- jwk.alg = 'RS256';
119
- return { keys: [jwk] };
120
- }
121
- /** Issue a JWT access token (typ="access") signed with the active alg. */
122
- async issueAccessToken(sub, expiresInSeconds = 3600) {
123
- if (!this.privateKey)
124
- throw new Error('JWTIssuer not initialized');
125
- return new jose.SignJWT({ sub, typ: 'access' })
126
- .setProtectedHeader({ alg: this.alg, kid: this.kid })
127
- .setIssuer(this.serverName)
128
- .setAudience(this.serverName)
129
- .setIssuedAt()
130
- .setExpirationTime(`${expiresInSeconds}s`)
131
- .sign(this.privateKey);
132
- }
133
- /**
134
- * Issue a JWT refresh token (typ="refresh") signed with the active alg.
135
- *
136
- * Defaults to a 1-year (31536000s) lifetime so long-running MCP clients can
137
- * mint fresh access tokens without forcing the user back through the browser
138
- * PKCE flow. The access token stays short-lived (1h); the refresh token is the
139
- * renewal credential and is rotated on every use (the /token refresh handler
140
- * issues a new refresh token each time), so the security control is rotation,
141
- * not a short TTL. A short refresh TTL was the residual re-auth driver: a
142
- * self-hosted server a user touches only intermittently (less than once a
143
- * month) would silently expire its refresh token between sessions, forcing a
144
- * fresh browser OAuth tab on the next use. With a 1-year floor, only a
145
- * genuinely long idle gap re-prompts. Same key / iss / aud as access tokens;
146
- * the typ claim is the only thing distinguishing them, and verifyAccessToken
147
- * rejects typ="refresh" so a refresh token can never be used as an access
148
- * token at the /mcp resource.
149
- */
150
- async issueRefreshToken(sub, expiresInSeconds = 31536000) {
151
- if (!this.privateKey)
152
- throw new Error('JWTIssuer not initialized');
153
- return new jose.SignJWT({ sub, typ: 'refresh' })
154
- .setProtectedHeader({ alg: this.alg, kid: this.kid })
155
- .setIssuer(this.serverName)
156
- .setAudience(this.serverName)
157
- .setIssuedAt()
158
- .setExpirationTime(`${expiresInSeconds}s`)
159
- .sign(this.privateKey);
160
- }
161
- /**
162
- * Verify a JWT access token and return its payload. Throws on failure (bad
163
- * signature, wrong issuer/audience, expired) — the same jose errors existing
164
- * callers already catch. The verify path uses the single active algorithm,
165
- * never a union. Additionally rejects tokens whose typ claim is "refresh"
166
- * (throwing jose.errors.JWTClaimValidationFailed) so a refresh token cannot
167
- * be replayed as an access token. Tokens with typ="access" OR a missing typ
168
- * claim are accepted (the latter keeps already-issued pre-refresh-support
169
- * tokens valid).
170
- */
171
- async verifyAccessToken(token) {
172
- if (!this.publicKey)
173
- throw new Error('JWTIssuer not initialized');
174
- const { payload } = await jose.jwtVerify(token, this.publicKey, {
175
- issuer: this.serverName,
176
- audience: this.serverName,
177
- algorithms: [this.alg]
178
- });
179
- if (payload.typ === 'refresh') {
180
- throw new jose.errors.JWTClaimValidationFailed('Refresh token cannot be used as an access token', payload, 'typ');
181
- }
182
- return payload;
183
- }
184
- /**
185
- * Verify a JWT refresh token and return its payload. Same key / audience /
186
- * issuer checks as verifyAccessToken and throws the same jose errors on
187
- * failure; uses the single active algorithm. Additionally asserts
188
- * typ=="refresh" (throwing jose.errors.JWTClaimValidationFailed otherwise) so
189
- * an access token can never be exchanged at the refresh grant.
190
- */
191
- async verifyRefreshToken(token) {
192
- if (!this.publicKey)
193
- throw new Error('JWTIssuer not initialized');
194
- const { payload } = await jose.jwtVerify(token, this.publicKey, {
195
- issuer: this.serverName,
196
- audience: this.serverName,
197
- algorithms: [this.alg]
198
- });
199
- if (payload.typ !== 'refresh') {
200
- throw new jose.errors.JWTClaimValidationFailed('Token is not a refresh token', payload, 'typ');
201
- }
202
- return payload;
203
- }
204
- }
205
- //# sourceMappingURL=jwt-issuer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jwt-issuer.js","sourceRoot":"","sources":["../../src/oauth/jwt-issuer.ts"],"names":[],"mappings":"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"}
@@ -1,10 +0,0 @@
1
- /**
2
- * Verify PKCE code challenge.
3
- * Throws an error if verification fails.
4
- *
5
- * @param codeVerifier The PKCE code verifier.
6
- * @param codeChallenge The stored code challenge.
7
- * @param method The code challenge method (S256 or plain).
8
- */
9
- export declare function verifyPKCE(codeVerifier: string, codeChallenge: string, method: string): void;
10
- //# sourceMappingURL=pkce.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAqB5F"}
@@ -1,34 +0,0 @@
1
- import { createHash, timingSafeEqual } from 'node:crypto';
2
- /**
3
- * Verify PKCE code challenge.
4
- * Throws an error if verification fails.
5
- *
6
- * @param codeVerifier The PKCE code verifier.
7
- * @param codeChallenge The stored code challenge.
8
- * @param method The code challenge method (S256 or plain).
9
- */
10
- export function verifyPKCE(codeVerifier, codeChallenge, method) {
11
- if (method === 'S256') {
12
- const digest = createHash('sha256').update(codeVerifier).digest('base64url');
13
- const expected = Buffer.from(digest);
14
- const actual = Buffer.from(codeChallenge);
15
- const isLengthEqual = expected.length === actual.length;
16
- const compareActual = isLengthEqual ? actual : expected;
17
- if (!timingSafeEqual(expected, compareActual) || !isLengthEqual) {
18
- throw new Error('invalid_grant: PKCE verification failed');
19
- }
20
- }
21
- else if (method === 'plain') {
22
- const expected = Buffer.from(codeVerifier);
23
- const actual = Buffer.from(codeChallenge);
24
- const isLengthEqual = expected.length === actual.length;
25
- const compareActual = isLengthEqual ? actual : expected;
26
- if (!timingSafeEqual(expected, compareActual) || !isLengthEqual) {
27
- throw new Error('invalid_grant: PKCE plain verification failed');
28
- }
29
- }
30
- else {
31
- throw new Error('unsupported_challenge_method');
32
- }
33
- }
34
- //# sourceMappingURL=pkce.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEzD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,YAAoB,EAAE,aAAqB,EAAE,MAAc;IACpF,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACzC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAA;QACvD,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QACvD,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACzC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAA;QACvD,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QACvD,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;QAClE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACjD,CAAC;AACH,CAAC"}
@@ -1,52 +0,0 @@
1
- /**
2
- * OAuth 2.1 Provider logic for TypeScript MCP servers.
3
- *
4
- * Implements the "MCP Server as Authorization Server" pattern.
5
- * The MCP Server issues JWTs, processes PKCE verification,
6
- * and uses the Relay Server purely as a UI consent transport.
7
- */
8
- import type { RelayConfigSchema } from '../schema/types.js';
9
- import { type IOAuthSessionCache } from './cache.js';
10
- import type { JWTIssuer } from './jwt-issuer.js';
11
- export { InMemoryAuthCache, type IOAuthSessionCache, type PreAuthSession } from './cache.js';
12
- export interface OAuthProviderOptions {
13
- serverName: string;
14
- relayBaseUrl: string;
15
- relaySchema: RelayConfigSchema;
16
- jwtIssuer: JWTIssuer;
17
- cache?: IOAuthSessionCache;
18
- }
19
- export declare class OAuthProvider {
20
- private serverName;
21
- private relayBaseUrl;
22
- private relaySchema;
23
- private jwtIssuer;
24
- private cache;
25
- constructor(options: OAuthProviderOptions);
26
- /**
27
- * Create a relay session and return the URL to redirect the user to.
28
- */
29
- createAuthorizeRedirect(clientId: string, redirectUri: string, state: string, codeChallenge: string, codeChallengeMethod?: string): Promise<string>;
30
- /**
31
- * Exchange the authorization code (relay session ID) for an access_token.
32
- * PKCE verification is performed.
33
- *
34
- * @param code The authorization code from the client.
35
- * @param codeVerifier The PKCE code verifier.
36
- * @param userIdExtractor Function to derive a unique user_id from the credentials.
37
- * @returns Tuple of [access_token, credentials]
38
- */
39
- exchangeCode(code: string, codeVerifier: string, userIdExtractor: (credentials: Record<string, string>) => string): Promise<{
40
- accessToken: string;
41
- credentials: Record<string, string>;
42
- }>;
43
- /**
44
- * Reconstruct relay session from pre-auth session.
45
- */
46
- private reconstructRelaySession;
47
- /**
48
- * Get RFC 8414 Authorization Server Metadata.
49
- */
50
- getMetadata(baseUrl: string): Record<string, unknown>;
51
- }
52
- //# sourceMappingURL=provider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAqB,KAAK,kBAAkB,EAAuB,MAAM,YAAY,CAAA;AAC5F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGhD,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,iBAAiB,CAAA;IAC9B,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,KAAK,CAAoB;IAEjC,YAAY,OAAO,EAAE,oBAAoB,EAMxC;IAED;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,mBAAmB,SAAS,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmBjB;IAED;;;;;;;;OAQG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,GAC/D,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAoBvE;IAED;;OAEG;YACW,uBAAuB;IAwBrC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWpD;CACF"}