mcp-trellis 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 (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +595 -0
  3. package/dist/adapters/node.d.ts +47 -0
  4. package/dist/adapters/node.d.ts.map +1 -0
  5. package/dist/adapters/node.js +116 -0
  6. package/dist/adapters/node.js.map +1 -0
  7. package/dist/app.d.ts +69 -0
  8. package/dist/app.d.ts.map +1 -0
  9. package/dist/app.js +101 -0
  10. package/dist/app.js.map +1 -0
  11. package/dist/auth/bearer.d.ts +21 -0
  12. package/dist/auth/bearer.d.ts.map +1 -0
  13. package/dist/auth/bearer.js +32 -0
  14. package/dist/auth/bearer.js.map +1 -0
  15. package/dist/clients.d.ts +33 -0
  16. package/dist/clients.d.ts.map +1 -0
  17. package/dist/clients.js +63 -0
  18. package/dist/clients.js.map +1 -0
  19. package/dist/dispatch.d.ts +7 -0
  20. package/dist/dispatch.d.ts.map +1 -0
  21. package/dist/dispatch.js +79 -0
  22. package/dist/dispatch.js.map +1 -0
  23. package/dist/http.d.ts +17 -0
  24. package/dist/http.d.ts.map +1 -0
  25. package/dist/http.js +38 -0
  26. package/dist/http.js.map +1 -0
  27. package/dist/jsonrpc.d.ts +32 -0
  28. package/dist/jsonrpc.d.ts.map +1 -0
  29. package/dist/jsonrpc.js +17 -0
  30. package/dist/jsonrpc.js.map +1 -0
  31. package/dist/methods.d.ts +52 -0
  32. package/dist/methods.d.ts.map +1 -0
  33. package/dist/methods.js +114 -0
  34. package/dist/methods.js.map +1 -0
  35. package/dist/oauth/authorize.d.ts +3 -0
  36. package/dist/oauth/authorize.d.ts.map +1 -0
  37. package/dist/oauth/authorize.js +109 -0
  38. package/dist/oauth/authorize.js.map +1 -0
  39. package/dist/oauth/base64url.d.ts +5 -0
  40. package/dist/oauth/base64url.d.ts.map +1 -0
  41. package/dist/oauth/base64url.js +17 -0
  42. package/dist/oauth/base64url.js.map +1 -0
  43. package/dist/oauth/clientauth.d.ts +19 -0
  44. package/dist/oauth/clientauth.d.ts.map +1 -0
  45. package/dist/oauth/clientauth.js +76 -0
  46. package/dist/oauth/clientauth.js.map +1 -0
  47. package/dist/oauth/codes.d.ts +30 -0
  48. package/dist/oauth/codes.d.ts.map +1 -0
  49. package/dist/oauth/codes.js +93 -0
  50. package/dist/oauth/codes.js.map +1 -0
  51. package/dist/oauth/constants.d.ts +32 -0
  52. package/dist/oauth/constants.d.ts.map +1 -0
  53. package/dist/oauth/constants.js +30 -0
  54. package/dist/oauth/constants.js.map +1 -0
  55. package/dist/oauth/metadata.d.ts +45 -0
  56. package/dist/oauth/metadata.d.ts.map +1 -0
  57. package/dist/oauth/metadata.js +36 -0
  58. package/dist/oauth/metadata.js.map +1 -0
  59. package/dist/oauth/pkce.d.ts +4 -0
  60. package/dist/oauth/pkce.d.ts.map +1 -0
  61. package/dist/oauth/pkce.js +17 -0
  62. package/dist/oauth/pkce.js.map +1 -0
  63. package/dist/oauth/redirect.d.ts +11 -0
  64. package/dist/oauth/redirect.d.ts.map +1 -0
  65. package/dist/oauth/redirect.js +26 -0
  66. package/dist/oauth/redirect.js.map +1 -0
  67. package/dist/oauth/resource.d.ts +7 -0
  68. package/dist/oauth/resource.d.ts.map +1 -0
  69. package/dist/oauth/resource.js +44 -0
  70. package/dist/oauth/resource.js.map +1 -0
  71. package/dist/oauth/revoke.d.ts +4 -0
  72. package/dist/oauth/revoke.d.ts.map +1 -0
  73. package/dist/oauth/revoke.js +30 -0
  74. package/dist/oauth/revoke.js.map +1 -0
  75. package/dist/oauth/router.d.ts +18 -0
  76. package/dist/oauth/router.d.ts.map +1 -0
  77. package/dist/oauth/router.js +105 -0
  78. package/dist/oauth/router.js.map +1 -0
  79. package/dist/oauth/scope.d.ts +11 -0
  80. package/dist/oauth/scope.d.ts.map +1 -0
  81. package/dist/oauth/scope.js +24 -0
  82. package/dist/oauth/scope.js.map +1 -0
  83. package/dist/oauth/token.d.ts +3 -0
  84. package/dist/oauth/token.d.ts.map +1 -0
  85. package/dist/oauth/token.js +137 -0
  86. package/dist/oauth/token.js.map +1 -0
  87. package/dist/oauth/types.d.ts +115 -0
  88. package/dist/oauth/types.d.ts.map +1 -0
  89. package/dist/oauth/types.js +28 -0
  90. package/dist/oauth/types.js.map +1 -0
  91. package/dist/oauth/wellknown.d.ts +8 -0
  92. package/dist/oauth/wellknown.d.ts.map +1 -0
  93. package/dist/oauth/wellknown.js +35 -0
  94. package/dist/oauth/wellknown.js.map +1 -0
  95. package/dist/protocol.d.ts +4 -0
  96. package/dist/protocol.d.ts.map +1 -0
  97. package/dist/protocol.js +14 -0
  98. package/dist/protocol.js.map +1 -0
  99. package/dist/registry.d.ts +37 -0
  100. package/dist/registry.d.ts.map +1 -0
  101. package/dist/registry.js +61 -0
  102. package/dist/registry.js.map +1 -0
  103. package/dist/server.d.ts +11 -0
  104. package/dist/server.d.ts.map +1 -0
  105. package/dist/server.js +11 -0
  106. package/dist/server.js.map +1 -0
  107. package/dist/tools.d.ts +80 -0
  108. package/dist/tools.d.ts.map +1 -0
  109. package/dist/tools.js +97 -0
  110. package/dist/tools.js.map +1 -0
  111. package/dist/validate.d.ts +23 -0
  112. package/dist/validate.d.ts.map +1 -0
  113. package/dist/validate.js +88 -0
  114. package/dist/validate.js.map +1 -0
  115. package/docs/diagrams/architecture.svg +1 -0
  116. package/docs/diagrams/first-connection.svg +1 -0
  117. package/docs/diagrams/ports.svg +1 -0
  118. package/package.json +68 -0
@@ -0,0 +1,93 @@
1
+ import { randomBase64Url } from "./pkce.js";
2
+ import { bytesToBase64Url, fromBase64Url, textToBase64Url } from "./base64url.js";
3
+ import { timingSafeEqual } from "../auth/bearer.js";
4
+ const CODE_TTL_MS = 600_000;
5
+ /**
6
+ * Process-local jti → expMs map when no shared codeStore is provided.
7
+ * ponytail: single-process only; multi-instance → pass ports.codeStore (KV/Redis SET NX EX).
8
+ */
9
+ const memoryUsed = new Map();
10
+ const pruneMemory = (nowMs) => {
11
+ [...memoryUsed].forEach(([jti, exp]) => {
12
+ if (exp < nowMs)
13
+ memoryUsed.delete(jti);
14
+ });
15
+ };
16
+ const memoryCodeStore = {
17
+ consume: (jti, expMs) => {
18
+ const nowMs = Date.now();
19
+ pruneMemory(nowMs);
20
+ if (memoryUsed.has(jti))
21
+ return false;
22
+ memoryUsed.set(jti, expMs);
23
+ return true;
24
+ },
25
+ };
26
+ const hmacSign = async (secret, payload) => {
27
+ const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
28
+ const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(payload));
29
+ return bytesToBase64Url(sig);
30
+ };
31
+ /**
32
+ * Issue an HMAC-signed auth code.
33
+ * Single-use via codeStore, or pruning in-memory Map when omitted.
34
+ */
35
+ export const issueAuthCode = async (secret, record, nowMs = Date.now()) => {
36
+ const body = {
37
+ ...record,
38
+ exp: nowMs + CODE_TTL_MS,
39
+ jti: randomBase64Url(12),
40
+ };
41
+ const payload = textToBase64Url(JSON.stringify(body));
42
+ const sig = await hmacSign(secret, payload);
43
+ return `${payload}.${sig}`;
44
+ };
45
+ export const consumeAuthCode = async (secret, code, options = {}) => {
46
+ if (!code || !secret)
47
+ return null;
48
+ const parts = code.split(".");
49
+ if (parts.length !== 2)
50
+ return null;
51
+ const [payload, sig] = parts;
52
+ if (!payload || !sig)
53
+ return null;
54
+ const expected = await hmacSign(secret, payload);
55
+ if (!timingSafeEqual(sig, expected))
56
+ return null;
57
+ try {
58
+ const raw = new TextDecoder().decode(fromBase64Url(payload));
59
+ const data = JSON.parse(raw);
60
+ const nowMs = options.nowMs ?? Date.now();
61
+ if (typeof data.clientId !== "string" ||
62
+ typeof data.redirectUri !== "string" ||
63
+ typeof data.codeChallenge !== "string" ||
64
+ typeof data.userId !== "string" ||
65
+ typeof data.resource !== "string" ||
66
+ data.resource.length === 0 ||
67
+ typeof data.scope !== "string" ||
68
+ typeof data.exp !== "number" ||
69
+ data.exp < nowMs) {
70
+ return null;
71
+ }
72
+ if (typeof data.jti !== "string" || data.jti.length === 0)
73
+ return null;
74
+ const store = options.codeStore ?? memoryCodeStore;
75
+ const fresh = await store.consume(data.jti, data.exp);
76
+ if (!fresh)
77
+ return null;
78
+ return {
79
+ clientId: data.clientId,
80
+ redirectUri: data.redirectUri,
81
+ codeChallenge: data.codeChallenge,
82
+ userId: data.userId,
83
+ resource: data.resource,
84
+ scope: data.scope,
85
+ exp: data.exp,
86
+ };
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ };
92
+ export const newClientId = () => randomBase64Url(16);
93
+ //# sourceMappingURL=codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.js","sourceRoot":"","sources":["../../src/oauth/codes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export declare const GRANT_TYPES: {
2
+ readonly authorizationCode: "authorization_code";
3
+ readonly refreshToken: "refresh_token";
4
+ };
5
+ export type GrantType = (typeof GRANT_TYPES)[keyof typeof GRANT_TYPES];
6
+ export declare const OAUTH_ERRORS: {
7
+ readonly invalidRequest: "invalid_request";
8
+ readonly invalidGrant: "invalid_grant";
9
+ readonly unsupportedGrantType: "unsupported_grant_type";
10
+ readonly invalidRedirectUri: "invalid_redirect_uri";
11
+ /** Token endpoint — client authentication failed, or the client is unknown. */
12
+ readonly invalidClient: "invalid_client";
13
+ /** Authorization endpoint — this client may not use this method. RFC 6749 §4.1.2.1. */
14
+ readonly unauthorizedClient: "unauthorized_client";
15
+ /** Requested scope exceeds what this server advertises. */
16
+ readonly invalidScope: "invalid_scope";
17
+ /** RFC 8707 — requested resource is not acceptable. */
18
+ readonly invalidTarget: "invalid_target";
19
+ /** A host port threw. RFC 6749 §4.1.2.1 / §5.2 — our fault, not the client's. */
20
+ readonly serverError: "server_error";
21
+ };
22
+ export declare const TOKEN_ENDPOINT_AUTH_METHODS: {
23
+ /** Public client — PKCE is the only proof. */
24
+ readonly none: "none";
25
+ /** Credentials in the Authorization header. */
26
+ readonly basic: "client_secret_basic";
27
+ /** Credentials in the request body. */
28
+ readonly post: "client_secret_post";
29
+ };
30
+ export type TokenEndpointAuthMethod = (typeof TOKEN_ENDPOINT_AUTH_METHODS)[keyof typeof TOKEN_ENDPOINT_AUTH_METHODS];
31
+ export declare const DEFAULT_SCOPE = "mcp";
32
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/oauth/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW;;;CAGd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEvE,eAAO,MAAM,YAAY;;;;;IAKvB,+EAA+E;;IAE/E,uFAAuF;;IAEvF,2DAA2D;;IAE3D,uDAAuD;;IAEvD,iFAAiF;;CAEzE,CAAC;AAEX,eAAO,MAAM,2BAA2B;IACtC,8CAA8C;;IAE9C,+CAA+C;;IAE/C,uCAAuC;;CAE/B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,OAAO,2BAA2B,CAAC,CAAC;AAEjF,eAAO,MAAM,aAAa,QAAQ,CAAC"}
@@ -0,0 +1,30 @@
1
+ export const GRANT_TYPES = {
2
+ authorizationCode: "authorization_code",
3
+ refreshToken: "refresh_token",
4
+ };
5
+ export const OAUTH_ERRORS = {
6
+ invalidRequest: "invalid_request",
7
+ invalidGrant: "invalid_grant",
8
+ unsupportedGrantType: "unsupported_grant_type",
9
+ invalidRedirectUri: "invalid_redirect_uri",
10
+ /** Token endpoint — client authentication failed, or the client is unknown. */
11
+ invalidClient: "invalid_client",
12
+ /** Authorization endpoint — this client may not use this method. RFC 6749 §4.1.2.1. */
13
+ unauthorizedClient: "unauthorized_client",
14
+ /** Requested scope exceeds what this server advertises. */
15
+ invalidScope: "invalid_scope",
16
+ /** RFC 8707 — requested resource is not acceptable. */
17
+ invalidTarget: "invalid_target",
18
+ /** A host port threw. RFC 6749 §4.1.2.1 / §5.2 — our fault, not the client's. */
19
+ serverError: "server_error",
20
+ };
21
+ export const TOKEN_ENDPOINT_AUTH_METHODS = {
22
+ /** Public client — PKCE is the only proof. */
23
+ none: "none",
24
+ /** Credentials in the Authorization header. */
25
+ basic: "client_secret_basic",
26
+ /** Credentials in the request body. */
27
+ post: "client_secret_post",
28
+ };
29
+ export const DEFAULT_SCOPE = "mcp";
30
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/oauth/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB,EAAE,oBAAoB;IACvC,YAAY,EAAE,eAAe;CACrB,CAAC;AAIX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,cAAc,EAAE,iBAAiB;IACjC,YAAY,EAAE,eAAe;IAC7B,oBAAoB,EAAE,wBAAwB;IAC9C,kBAAkB,EAAE,sBAAsB;IAC1C,+EAA+E;IAC/E,aAAa,EAAE,gBAAgB;IAC/B,uFAAuF;IACvF,kBAAkB,EAAE,qBAAqB;IACzC,2DAA2D;IAC3D,YAAY,EAAE,eAAe;IAC7B,uDAAuD;IACvD,aAAa,EAAE,gBAAgB;IAC/B,iFAAiF;IACjF,WAAW,EAAE,cAAc;CACnB,CAAC;AAEX,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,8CAA8C;IAC9C,IAAI,EAAE,MAAM;IACZ,+CAA+C;IAC/C,KAAK,EAAE,qBAAqB;IAC5B,uCAAuC;IACvC,IAAI,EAAE,oBAAoB;CAClB,CAAC;AAKX,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { type GrantType, type TokenEndpointAuthMethod } from "./constants.js";
2
+ export type { GrantType } from "./constants.js";
3
+ export type ProtectedResourceMetadata = {
4
+ resource: string;
5
+ authorization_servers: string[];
6
+ bearer_methods_supported: string[];
7
+ scopes_supported: string[];
8
+ };
9
+ export type AuthorizationServerMetadata = {
10
+ issuer: string;
11
+ authorization_endpoint: string;
12
+ token_endpoint: string;
13
+ /** Omitted when this server does not accept dynamically registered clients. */
14
+ registration_endpoint?: string;
15
+ response_types_supported: string[];
16
+ grant_types_supported: string[];
17
+ code_challenge_methods_supported: string[];
18
+ token_endpoint_auth_methods_supported: TokenEndpointAuthMethod[];
19
+ scopes_supported: string[];
20
+ /** RFC 8707 — clients must send `resource` on authorize/token. */
21
+ resource_parameter_supported: boolean;
22
+ /** Omitted when `revokeToken` is not configured. */
23
+ revocation_endpoint?: string;
24
+ revocation_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
25
+ };
26
+ export type MetadataOptions = {
27
+ origin: string;
28
+ /** MCP resource path, e.g. "/mcp". */
29
+ resourcePath?: string;
30
+ /** OAuth path prefix, e.g. "/mcp/oauth". */
31
+ oauthPath?: string;
32
+ /** Only advertise grants that are actually handled. */
33
+ grantTypes: GrantType[];
34
+ scopes?: string[];
35
+ /** Only advertise auth methods the configured clients actually use. */
36
+ tokenEndpointAuthMethods?: TokenEndpointAuthMethod[];
37
+ /** Advertise `registration_endpoint`. Default true. */
38
+ dcrEnabled?: boolean;
39
+ /** Advertise `revocation_endpoint`. Default false. */
40
+ revocationEnabled?: boolean;
41
+ };
42
+ export declare const protectedResourceMetadata: (options: MetadataOptions) => ProtectedResourceMetadata;
43
+ export declare const authorizationServerMetadata: (options: MetadataOptions) => AuthorizationServerMetadata;
44
+ export declare const mcpWwwAuthenticate: (origin: string, resourcePath?: string, realm?: string) => string;
45
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gCAAgC,EAAE,MAAM,EAAE,CAAC;IAC3C,qCAAqC,EAAE,uBAAuB,EAAE,CAAC;IACjE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kEAAkE;IAClE,4BAA4B,EAAE,OAAO,CAAC;IACtC,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACxE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrD,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,SAAS,eAAe,KACvB,yBAKD,CAAC;AAEH,eAAO,MAAM,2BAA2B,GACtC,SAAS,eAAe,KACvB,2BAyBF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,MAAM,EACd,qBAAoC,EACpC,cAAa,KACZ,MAC2G,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { DEFAULT_SCOPE, TOKEN_ENDPOINT_AUTH_METHODS, } from "./constants.js";
2
+ import { canonicalResource, DEFAULT_RESOURCE_PATH } from "./resource.js";
3
+ export const protectedResourceMetadata = (options) => ({
4
+ resource: canonicalResource(options.origin, options.resourcePath),
5
+ authorization_servers: [options.origin],
6
+ bearer_methods_supported: ["header"],
7
+ scopes_supported: options.scopes ?? [DEFAULT_SCOPE],
8
+ });
9
+ export const authorizationServerMetadata = (options) => {
10
+ const oauthPath = options.oauthPath ?? "/mcp/oauth";
11
+ const tokenEndpointAuthMethods = options.tokenEndpointAuthMethods ?? [
12
+ TOKEN_ENDPOINT_AUTH_METHODS.none,
13
+ ];
14
+ return {
15
+ issuer: options.origin,
16
+ authorization_endpoint: `${options.origin}${oauthPath}/authorize`,
17
+ token_endpoint: `${options.origin}${oauthPath}/token`,
18
+ ...(options.dcrEnabled !== false
19
+ ? { registration_endpoint: `${options.origin}${oauthPath}/register` }
20
+ : {}),
21
+ ...(options.revocationEnabled
22
+ ? {
23
+ revocation_endpoint: `${options.origin}${oauthPath}/revoke`,
24
+ revocation_endpoint_auth_methods_supported: tokenEndpointAuthMethods,
25
+ }
26
+ : {}),
27
+ response_types_supported: ["code"],
28
+ grant_types_supported: [...options.grantTypes],
29
+ code_challenge_methods_supported: ["S256"],
30
+ token_endpoint_auth_methods_supported: tokenEndpointAuthMethods,
31
+ scopes_supported: options.scopes ?? [DEFAULT_SCOPE],
32
+ resource_parameter_supported: true,
33
+ };
34
+ };
35
+ export const mcpWwwAuthenticate = (origin, resourcePath = DEFAULT_RESOURCE_PATH, realm = "mcp") => `Bearer realm="${realm}", resource_metadata="${origin}/.well-known/oauth-protected-resource${resourcePath}"`;
36
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,2BAA2B,GAG5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AA8CzE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAwB,EACG,EAAE,CAAC,CAAC;IAC/B,QAAQ,EAAE,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC;IACjE,qBAAqB,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;IACpC,gBAAgB,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC;CACpD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,OAAwB,EACK,EAAE;IAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,YAAY,CAAC;IACpD,MAAM,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,IAAI;QACnE,2BAA2B,CAAC,IAAI;KACjC,CAAC;IACF,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,sBAAsB,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,YAAY;QACjE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,QAAQ;QACrD,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,KAAK;YAC9B,CAAC,CAAC,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,WAAW,EAAE;YACrE,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,iBAAiB;YAC3B,CAAC,CAAC;gBACE,mBAAmB,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,SAAS;gBAC3D,0CAA0C,EAAE,wBAAwB;aACrE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,qBAAqB,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QAC9C,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,qCAAqC,EAAE,wBAAwB;QAC/D,gBAAgB,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC;QACnD,4BAA4B,EAAE,IAAI;KACnC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,MAAc,EACd,YAAY,GAAG,qBAAqB,EACpC,KAAK,GAAG,KAAK,EACL,EAAE,CACV,iBAAiB,KAAK,yBAAyB,MAAM,wCAAwC,YAAY,GAAG,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const sha256Base64Url: (input: string) => Promise<string>;
2
+ export declare const verifyPkceS256: (verifier: string, challenge: string) => Promise<boolean>;
3
+ export declare const randomBase64Url: (byteLen: number) => string;
4
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,CAMnE,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,UAAU,MAAM,EAChB,WAAW,MAAM,KAChB,OAAO,CAAC,OAAO,CAIjB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAGjD,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { bytesToBase64Url } from "./base64url.js";
2
+ import { timingSafeEqual } from "../auth/bearer.js";
3
+ export const sha256Base64Url = async (input) => {
4
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
5
+ return bytesToBase64Url(digest);
6
+ };
7
+ export const verifyPkceS256 = async (verifier, challenge) => {
8
+ if (!verifier || !challenge)
9
+ return false;
10
+ const computed = await sha256Base64Url(verifier);
11
+ return timingSafeEqual(computed, challenge);
12
+ };
13
+ export const randomBase64Url = (byteLen) => {
14
+ const bytes = crypto.getRandomValues(new Uint8Array(byteLen));
15
+ return bytesToBase64Url(bytes);
16
+ };
17
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,KAAa,EAAmB,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACvC,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAChC,CAAC;IACF,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,QAAgB,EAChB,SAAiB,EACC,EAAE;IACpB,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAU,EAAE;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const CLAUDE_CALLBACK = "https://claude.ai/api/mcp/auth_callback";
2
+ export type RedirectAllowlistOptions = {
3
+ /** Extra exact-match redirect URIs. */
4
+ extra?: string[];
5
+ /** Allow http(s) loopback hosts — 127.0.0.1, [::1], localhost (any port). Default true. */
6
+ allowLoopback?: boolean;
7
+ /** Allow the Claude.ai Custom Connector callback. Default true. */
8
+ allowClaude?: boolean;
9
+ };
10
+ export declare const isAllowedRedirectUri: (uri: string, options?: RedirectAllowlistOptions) => boolean;
11
+ //# sourceMappingURL=redirect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../../src/oauth/redirect.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,4CAA4C,CAAC;AAEzE,MAAM,MAAM,wBAAwB,GAAG;IACrC,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAmCF,eAAO,MAAM,oBAAoB,GAC/B,KAAK,MAAM,EACX,UAAS,wBAA6B,KACrC,OAA2E,CAAC"}
@@ -0,0 +1,26 @@
1
+ export const CLAUDE_CALLBACK = "https://claude.ai/api/mcp/auth_callback";
2
+ const isClaudeCallback = (uri, options) => options.allowClaude !== false && uri === CLAUDE_CALLBACK;
3
+ const isExtraAllowed = (uri, options) => Boolean(options.extra?.includes(uri));
4
+ /** WHATWG URL keeps IPv6 hosts bracketed, so `[::1]` is the parsed hostname. */
5
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "[::1]", "localhost"]);
6
+ const isLoopbackHttp = (uri, options) => {
7
+ if (options.allowLoopback === false)
8
+ return false;
9
+ try {
10
+ const parsed = new URL(uri);
11
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
12
+ return false;
13
+ }
14
+ return LOOPBACK_HOSTS.has(parsed.hostname);
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ };
20
+ const REDIRECT_PREDICATES = [
21
+ isClaudeCallback,
22
+ isExtraAllowed,
23
+ isLoopbackHttp,
24
+ ];
25
+ export const isAllowedRedirectUri = (uri, options = {}) => REDIRECT_PREDICATES.some((predicate) => predicate(uri, options));
26
+ //# sourceMappingURL=redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.js","sourceRoot":"","sources":["../../src/oauth/redirect.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,yCAAyC,CAAC;AAgBzE,MAAM,gBAAgB,GAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAC3D,OAAO,CAAC,WAAW,KAAK,KAAK,IAAI,GAAG,KAAK,eAAe,CAAC;AAE3D,MAAM,cAAc,GAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CACzD,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAExC,gFAAgF;AAChF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;AAEpE,MAAM,cAAc,GAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;IACzD,IAAI,OAAO,CAAC,aAAa,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAwB;IAC/C,gBAAgB;IAChB,cAAc;IACd,cAAc;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,GAAW,EACX,UAAoC,EAAE,EAC7B,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** Canonical MCP resource URI (RFC 8707 / RFC 9728). */
2
+ export declare const DEFAULT_RESOURCE_PATH = "/mcp";
3
+ export declare const canonicalResource: (origin: string, resourcePath?: string) => string;
4
+ export declare const resourcesEqual: (requested: string, expected: string) => boolean;
5
+ /** Missing → invalid_request; mismatch → invalid_target. */
6
+ export declare const firstResourceError: (requested: string, expected: string) => Response | null;
7
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/oauth/resource.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAKxD,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAE5C,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,qBAAoC,KACnC,MAMF,CAAC;AAmBF,eAAO,MAAM,cAAc,GACzB,WAAW,MAAM,EACjB,UAAU,MAAM,KACf,OAGF,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,UAAU,MAAM,KACf,QAAQ,GAAG,IAgBb,CAAC"}
@@ -0,0 +1,44 @@
1
+ /** Canonical MCP resource URI (RFC 8707 / RFC 9728). */
2
+ import { OAUTH_ERRORS } from "./constants.js";
3
+ import { oauthError } from "./types.js";
4
+ export const DEFAULT_RESOURCE_PATH = "/mcp";
5
+ export const canonicalResource = (origin, resourcePath = DEFAULT_RESOURCE_PATH) => {
6
+ const base = origin.replace(/\/$/, "");
7
+ const path = resourcePath.startsWith("/")
8
+ ? resourcePath
9
+ : `/${resourcePath}`;
10
+ return `${base}${path}`;
11
+ };
12
+ /**
13
+ * Normalize for RFC 8707 comparison.
14
+ * Rejects fragments (MUST NOT). Includes query so tenants cannot alias.
15
+ * ponytail: exact match after WHATWG URL parse; upgrade to RFC 3986 if
16
+ * non-ASCII hosts or exotic percent-encoding show up.
17
+ */
18
+ const normalizeResource = (uri) => {
19
+ try {
20
+ const u = new URL(uri);
21
+ if (u.hash)
22
+ return null;
23
+ const path = u.pathname.replace(/\/$/, "") || "/";
24
+ return `${u.protocol}//${u.host}${path}${u.search}`;
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ };
30
+ export const resourcesEqual = (requested, expected) => {
31
+ const a = normalizeResource(requested);
32
+ return a !== null && a === normalizeResource(expected);
33
+ };
34
+ /** Missing → invalid_request; mismatch → invalid_target. */
35
+ export const firstResourceError = (requested, expected) => {
36
+ if (!requested) {
37
+ return oauthError(OAUTH_ERRORS.invalidRequest, 400, "resource required (RFC 8707)");
38
+ }
39
+ if (!resourcesEqual(requested, expected)) {
40
+ return oauthError(OAUTH_ERRORS.invalidTarget, 400, "resource does not match this server");
41
+ }
42
+ return null;
43
+ };
44
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/oauth/resource.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAc,EACd,YAAY,GAAG,qBAAqB,EAC5B,EAAE;IACV,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;QACvC,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC;IACvB,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AAC1B,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAiB,EAAE;IACvD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;QAClD,OAAO,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,SAAiB,EACjB,QAAgB,EACP,EAAE;IACX,MAAM,CAAC,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,SAAiB,EACjB,QAAgB,EACC,EAAE;IACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,UAAU,CACf,YAAY,CAAC,cAAc,EAC3B,GAAG,EACH,8BAA8B,CAC/B,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;QACzC,OAAO,UAAU,CACf,YAAY,CAAC,aAAa,EAC1B,GAAG,EACH,qCAAqC,CACtC,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** RFC 7009 token revocation. */
2
+ import { type OAuthRouterOptions } from "./types.js";
3
+ export declare const handleRevoke: (request: Request, options: OAuthRouterOptions) => Promise<Response>;
4
+ //# sourceMappingURL=revoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/oauth/revoke.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAKjC,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAUjE,eAAO,MAAM,YAAY,GACvB,SAAS,OAAO,EAChB,SAAS,kBAAkB,KAC1B,OAAO,CAAC,QAAQ,CAuBlB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /** RFC 7009 token revocation. */
2
+ import { requireHttpMethod } from "../http.js";
3
+ import { firstClientAuthError, readClientAuth } from "./clientauth.js";
4
+ import { OAUTH_ERRORS } from "./constants.js";
5
+ import { oauthError } from "./types.js";
6
+ const POST_ONLY = new Set(["POST"]);
7
+ const NO_CORS = { cors: false };
8
+ const tokenTypeHintOf = (hint) => hint === "access_token" || hint === "refresh_token" ? hint : undefined;
9
+ export const handleRevoke = async (request, options) => {
10
+ const methodError = requireHttpMethod(request, POST_ONLY, NO_CORS);
11
+ if (methodError)
12
+ return methodError;
13
+ const body = Object.fromEntries(new URLSearchParams(await request.text()).entries());
14
+ const token = body.token ?? "";
15
+ if (!token)
16
+ return oauthError(OAUTH_ERRORS.invalidRequest, 400, "token required");
17
+ const auth = readClientAuth(request, body);
18
+ if (!auth)
19
+ return oauthError(OAUTH_ERRORS.invalidRequest, 400, "client_id required");
20
+ const clientAuthError = await firstClientAuthError(auth, options);
21
+ if (clientAuthError)
22
+ return clientAuthError;
23
+ await options.ports.revokeToken?.({
24
+ token,
25
+ clientId: auth.clientId,
26
+ tokenTypeHint: tokenTypeHintOf(body.token_type_hint),
27
+ });
28
+ return new Response(null, { status: 200, headers: { "Cache-Control": "no-store" } });
29
+ };
30
+ //# sourceMappingURL=revoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../../src/oauth/revoke.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAEjE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpC,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,KAAK,EAAW,CAAC;AAEzC,MAAM,eAAe,GAAG,CACtB,IAAwB,EACsB,EAAE,CAChD,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAEzE,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,OAAgB,EAChB,OAA2B,EACR,EAAE;IACrB,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACnE,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAC7B,IAAI,eAAe,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CACpD,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO,UAAU,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAElF,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,UAAU,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAErF,MAAM,eAAe,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClE,IAAI,eAAe;QAAE,OAAO,eAAe,CAAC;IAE5C,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAChC,KAAK;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,aAAa,EAAE,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC;KACrD,CAAC,CAAC;IAEH,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;AACvF,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type OAuthRouterOptions } from "./types.js";
2
+ export type { OAuthUser, MintedToken, OAuthPorts, OAuthRouterOptions, } from "./types.js";
3
+ export type OAuthRouter = {
4
+ /** Returns a Response when this request is OAuth-related; otherwise null. */
5
+ tryHandle: (request: Request) => Promise<Response | null>;
6
+ };
7
+ export declare const createOAuthRouter: (options: OAuthRouterOptions) => OAuthRouter;
8
+ export { authorizationServerMetadata, protectedResourceMetadata, mcpWwwAuthenticate, } from "./metadata.js";
9
+ export { canonicalResource, resourcesEqual, DEFAULT_RESOURCE_PATH, firstResourceError, } from "./resource.js";
10
+ export { isAllowedRedirectUri, CLAUDE_CALLBACK } from "./redirect.js";
11
+ export { issueAuthCode, consumeAuthCode, newClientId, type AuthCodeRecord, type CodeStore, } from "./codes.js";
12
+ export { verifyPkceS256, sha256Base64Url, randomBase64Url } from "./pkce.js";
13
+ export { GRANT_TYPES, OAUTH_ERRORS, DEFAULT_SCOPE, TOKEN_ENDPOINT_AUTH_METHODS, type TokenEndpointAuthMethod, } from "./constants.js";
14
+ export { parseScope, formatScope, requestedScopes, firstScopeError, } from "./scope.js";
15
+ export { readClientAuth, firstClientAuthError, type ClientAuth } from "./clientauth.js";
16
+ export { unregisteredClientsAllowed } from "./types.js";
17
+ export type { MintAccessTokenInput, RefreshAccessTokenInput, RevokeTokenInput, ClientStore, RegisteredClient, } from "./types.js";
18
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/oauth/router.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,MAAM,YAAY,CAAC;AA4CpB,MAAM,MAAM,WAAW,GAAG;IACxB,6EAA6E;IAC7E,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CAC3D,CAAC;AAIF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,kBAAkB,KAC1B,WA4DF,CAAC;AAEF,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EACL,aAAa,EACb,eAAe,EACf,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,2BAA2B,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,UAAU,EACV,WAAW,EACX,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACxD,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,105 @@
1
+ import { INTERNAL_ERROR, jsonResponse, requireHttpMethod } from "../http.js";
2
+ import { newClientId } from "./codes.js";
3
+ import { GRANT_TYPES, OAUTH_ERRORS } from "./constants.js";
4
+ import { CLAUDE_CALLBACK, isAllowedRedirectUri } from "./redirect.js";
5
+ import { DEFAULT_RESOURCE_PATH } from "./resource.js";
6
+ import { oauthError, unregisteredClientsAllowed, } from "./types.js";
7
+ import { handleAuthorize } from "./authorize.js";
8
+ import { handleToken } from "./token.js";
9
+ import { handleRevoke } from "./revoke.js";
10
+ import { handleWellKnown } from "./wellknown.js";
11
+ const POST_ONLY = new Set(["POST"]);
12
+ const handleRegister = async (request, options) => {
13
+ const methodError = requireHttpMethod(request, POST_ONLY);
14
+ if (methodError)
15
+ return methodError;
16
+ let suppliedRedirectUris = false;
17
+ let redirectUris = [];
18
+ try {
19
+ const body = (await request.json());
20
+ const raw = body.redirect_uris;
21
+ if (Array.isArray(raw)) {
22
+ suppliedRedirectUris = true;
23
+ redirectUris = raw
24
+ .map((u) => String(u))
25
+ .filter((uri) => isAllowedRedirectUri(uri, options.redirect));
26
+ }
27
+ }
28
+ catch {
29
+ redirectUris = [];
30
+ }
31
+ if (suppliedRedirectUris && redirectUris.length === 0) {
32
+ return oauthError(OAUTH_ERRORS.invalidRedirectUri, 400, "no allowed redirect_uris");
33
+ }
34
+ return jsonResponse({
35
+ client_id: newClientId(),
36
+ client_id_issued_at: Math.floor(Date.now() / 1000),
37
+ token_endpoint_auth_method: "none",
38
+ redirect_uris: redirectUris.length > 0 ? redirectUris : [CLAUDE_CALLBACK],
39
+ grant_types: [GRANT_TYPES.authorizationCode],
40
+ response_types: ["code"],
41
+ });
42
+ };
43
+ export const createOAuthRouter = (options) => {
44
+ if (!unregisteredClientsAllowed(options) && !options.ports.clientStore) {
45
+ throw new Error("allowUnregisteredClients: false requires ports.clientStore " +
46
+ "so pre-registered clients can be resolved");
47
+ }
48
+ const resourcePath = options.resourcePath ?? DEFAULT_RESOURCE_PATH;
49
+ const oauthPath = options.oauthPath ?? "/mcp/oauth";
50
+ const prmPaths = new Set([
51
+ "/.well-known/oauth-protected-resource",
52
+ `/.well-known/oauth-protected-resource${resourcePath}`,
53
+ ]);
54
+ const asPaths = new Set([
55
+ "/.well-known/oauth-authorization-server",
56
+ `/.well-known/oauth-authorization-server${resourcePath}`,
57
+ ]);
58
+ const routes = {
59
+ ...(unregisteredClientsAllowed(options)
60
+ ? {
61
+ [`${oauthPath}/register`]: (request) => handleRegister(request, options),
62
+ }
63
+ : {}),
64
+ [`${oauthPath}/authorize`]: (request) => handleAuthorize(request, options),
65
+ [`${oauthPath}/token`]: (request) => handleToken(request, options),
66
+ ...(options.ports.revokeToken
67
+ ? {
68
+ [`${oauthPath}/revoke`]: (request) => handleRevoke(request, options),
69
+ }
70
+ : {}),
71
+ };
72
+ return {
73
+ tryHandle: async (request) => {
74
+ try {
75
+ const path = new URL(request.url).pathname;
76
+ const known = await handleWellKnown(request, options, {
77
+ prmPaths,
78
+ asPaths,
79
+ resourcePath,
80
+ oauthPath,
81
+ });
82
+ if (known)
83
+ return known;
84
+ const route = routes[path];
85
+ return route ? await route(request) : null;
86
+ }
87
+ catch {
88
+ // A host port (resolveUser/mintAccessToken/clientStore/...) threw.
89
+ // We only ever reach here on a route this router owns, so answer
90
+ // with a real error instead of throwing out of `tryHandle`.
91
+ return oauthError(OAUTH_ERRORS.serverError, 500, INTERNAL_ERROR);
92
+ }
93
+ },
94
+ };
95
+ };
96
+ export { authorizationServerMetadata, protectedResourceMetadata, mcpWwwAuthenticate, } from "./metadata.js";
97
+ export { canonicalResource, resourcesEqual, DEFAULT_RESOURCE_PATH, firstResourceError, } from "./resource.js";
98
+ export { isAllowedRedirectUri, CLAUDE_CALLBACK } from "./redirect.js";
99
+ export { issueAuthCode, consumeAuthCode, newClientId, } from "./codes.js";
100
+ export { verifyPkceS256, sha256Base64Url, randomBase64Url } from "./pkce.js";
101
+ export { GRANT_TYPES, OAUTH_ERRORS, DEFAULT_SCOPE, TOKEN_ENDPOINT_AUTH_METHODS, } from "./constants.js";
102
+ export { parseScope, formatScope, requestedScopes, firstScopeError, } from "./scope.js";
103
+ export { readClientAuth, firstClientAuthError } from "./clientauth.js";
104
+ export { unregisteredClientsAllowed } from "./types.js";
105
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/oauth/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** OAuth scope handling — space-delimited sets (RFC 6749 §3.3). */
2
+ export declare const parseScope: (raw: string) => string[];
3
+ export declare const formatScope: (scopes: string[]) => string;
4
+ /**
5
+ * Scopes the client asked for, or the full advertised set when `scope` is omitted.
6
+ * Duplicates are collapsed so the granted string is stable.
7
+ */
8
+ export declare const requestedScopes: (raw: string, advertised: string[]) => string[];
9
+ /** Any scope outside the advertised set → invalid_scope. */
10
+ export declare const firstScopeError: (requested: string[], advertised: string[]) => Response | null;
11
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/oauth/scope.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAKnE,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MAAM,EAIP,CAAC;AAEzC,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,KAAG,MAA0B,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK,MAAM,EACX,YAAY,MAAM,EAAE,KACnB,MAAM,EAGR,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,eAAe,GAC1B,WAAW,MAAM,EAAE,EACnB,YAAY,MAAM,EAAE,KACnB,QAAQ,GAAG,IAQb,CAAC"}