mcp-trellis 0.2.1 → 1.0.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 (131) hide show
  1. package/README.md +41 -561
  2. package/dist/adapters/node.d.ts +14 -5
  3. package/dist/adapters/node.d.ts.map +1 -1
  4. package/dist/adapters/node.js +56 -29
  5. package/dist/adapters/node.js.map +1 -1
  6. package/dist/adapters/origins.d.ts.map +1 -1
  7. package/dist/adapters/origins.js +1 -4
  8. package/dist/adapters/origins.js.map +1 -1
  9. package/dist/app.d.ts +27 -4
  10. package/dist/app.d.ts.map +1 -1
  11. package/dist/app.js +31 -18
  12. package/dist/app.js.map +1 -1
  13. package/dist/auth/bearer.d.ts.map +1 -1
  14. package/dist/auth/bearer.js +6 -1
  15. package/dist/auth/bearer.js.map +1 -1
  16. package/dist/body.d.ts +48 -0
  17. package/dist/body.d.ts.map +1 -0
  18. package/dist/body.js +145 -0
  19. package/dist/body.js.map +1 -0
  20. package/dist/clients.d.ts.map +1 -1
  21. package/dist/clients.js +2 -5
  22. package/dist/clients.js.map +1 -1
  23. package/dist/dispatch.d.ts +1 -1
  24. package/dist/dispatch.d.ts.map +1 -1
  25. package/dist/dispatch.js +58 -18
  26. package/dist/dispatch.js.map +1 -1
  27. package/dist/http.d.ts.map +1 -1
  28. package/dist/http.js.map +1 -1
  29. package/dist/jsonrpc.d.ts +1 -0
  30. package/dist/jsonrpc.d.ts.map +1 -1
  31. package/dist/jsonrpc.js +1 -0
  32. package/dist/jsonrpc.js.map +1 -1
  33. package/dist/methods.d.ts +38 -15
  34. package/dist/methods.d.ts.map +1 -1
  35. package/dist/methods.js +38 -22
  36. package/dist/methods.js.map +1 -1
  37. package/dist/oauth/authorize.d.ts.map +1 -1
  38. package/dist/oauth/authorize.js +100 -68
  39. package/dist/oauth/authorize.js.map +1 -1
  40. package/dist/oauth/base64url.d.ts +1 -1
  41. package/dist/oauth/base64url.d.ts.map +1 -1
  42. package/dist/oauth/base64url.js +1 -4
  43. package/dist/oauth/base64url.js.map +1 -1
  44. package/dist/oauth/clientauth.d.ts +7 -2
  45. package/dist/oauth/clientauth.d.ts.map +1 -1
  46. package/dist/oauth/clientauth.js +59 -16
  47. package/dist/oauth/clientauth.js.map +1 -1
  48. package/dist/oauth/codes.d.ts +4 -4
  49. package/dist/oauth/codes.d.ts.map +1 -1
  50. package/dist/oauth/codes.js +43 -51
  51. package/dist/oauth/codes.js.map +1 -1
  52. package/dist/oauth/consent.d.ts +65 -0
  53. package/dist/oauth/consent.d.ts.map +1 -0
  54. package/dist/oauth/consent.js +173 -0
  55. package/dist/oauth/consent.js.map +1 -0
  56. package/dist/oauth/constants.d.ts +4 -0
  57. package/dist/oauth/constants.d.ts.map +1 -1
  58. package/dist/oauth/constants.js +4 -0
  59. package/dist/oauth/constants.js.map +1 -1
  60. package/dist/oauth/metadata.d.ts +6 -6
  61. package/dist/oauth/metadata.d.ts.map +1 -1
  62. package/dist/oauth/metadata.js.map +1 -1
  63. package/dist/oauth/pkce.d.ts.map +1 -1
  64. package/dist/oauth/pkce.js +1 -1
  65. package/dist/oauth/pkce.js.map +1 -1
  66. package/dist/oauth/redirect.d.ts +6 -1
  67. package/dist/oauth/redirect.d.ts.map +1 -1
  68. package/dist/oauth/redirect.js +23 -10
  69. package/dist/oauth/redirect.js.map +1 -1
  70. package/dist/oauth/reqbody.d.ts +10 -0
  71. package/dist/oauth/reqbody.d.ts.map +1 -0
  72. package/dist/oauth/reqbody.js +29 -0
  73. package/dist/oauth/reqbody.js.map +1 -0
  74. package/dist/oauth/resource.d.ts +30 -0
  75. package/dist/oauth/resource.d.ts.map +1 -1
  76. package/dist/oauth/resource.js +38 -8
  77. package/dist/oauth/resource.js.map +1 -1
  78. package/dist/oauth/revoke.d.ts.map +1 -1
  79. package/dist/oauth/revoke.js +15 -3
  80. package/dist/oauth/revoke.js.map +1 -1
  81. package/dist/oauth/router.d.ts +14 -11
  82. package/dist/oauth/router.d.ts.map +1 -1
  83. package/dist/oauth/router.js +62 -22
  84. package/dist/oauth/router.js.map +1 -1
  85. package/dist/oauth/scope.d.ts +11 -2
  86. package/dist/oauth/scope.d.ts.map +1 -1
  87. package/dist/oauth/scope.js +18 -7
  88. package/dist/oauth/scope.js.map +1 -1
  89. package/dist/oauth/sealed.d.ts +17 -0
  90. package/dist/oauth/sealed.d.ts.map +1 -0
  91. package/dist/oauth/sealed.js +57 -0
  92. package/dist/oauth/sealed.js.map +1 -0
  93. package/dist/oauth/secrethash.d.ts +44 -0
  94. package/dist/oauth/secrethash.d.ts.map +1 -0
  95. package/dist/oauth/secrethash.js +66 -0
  96. package/dist/oauth/secrethash.js.map +1 -0
  97. package/dist/oauth/token.d.ts.map +1 -1
  98. package/dist/oauth/token.js +13 -34
  99. package/dist/oauth/token.js.map +1 -1
  100. package/dist/oauth/types.d.ts +106 -9
  101. package/dist/oauth/types.d.ts.map +1 -1
  102. package/dist/oauth/types.js +67 -4
  103. package/dist/oauth/types.js.map +1 -1
  104. package/dist/oauth/wellknown.d.ts.map +1 -1
  105. package/dist/oauth/wellknown.js +6 -4
  106. package/dist/oauth/wellknown.js.map +1 -1
  107. package/dist/protocol.d.ts +15 -1
  108. package/dist/protocol.d.ts.map +1 -1
  109. package/dist/protocol.js +16 -6
  110. package/dist/protocol.js.map +1 -1
  111. package/dist/registry.d.ts +4 -4
  112. package/dist/registry.d.ts.map +1 -1
  113. package/dist/registry.js +15 -7
  114. package/dist/registry.js.map +1 -1
  115. package/dist/server.d.ts +14 -13
  116. package/dist/server.d.ts.map +1 -1
  117. package/dist/server.js +8 -8
  118. package/dist/server.js.map +1 -1
  119. package/dist/tools.d.ts +11 -2
  120. package/dist/tools.d.ts.map +1 -1
  121. package/dist/tools.js +14 -13
  122. package/dist/tools.js.map +1 -1
  123. package/dist/validate.d.ts +16 -1
  124. package/dist/validate.d.ts.map +1 -1
  125. package/dist/validate.js +46 -8
  126. package/dist/validate.js.map +1 -1
  127. package/docs/ROADMAP.md +295 -0
  128. package/docs/guide.md +417 -0
  129. package/docs/reference.md +178 -0
  130. package/docs/security.md +63 -0
  131. package/package.json +6 -3
@@ -1,7 +1,8 @@
1
1
  import { randomBase64Url } from "./pkce.js";
2
- import { bytesToBase64Url, fromBase64Url, textToBase64Url } from "./base64url.js";
3
- import { timingSafeEqual } from "../auth/bearer.js";
2
+ import { seal, unseal } from "./sealed.js";
4
3
  const CODE_TTL_MS = 600_000;
4
+ /** AES-GCM sealed auth codes — authenticated and encrypted (see `sealed.ts`). */
5
+ const SEALED_PREFIX = "v2.";
5
6
  /**
6
7
  * Process-local jti → expMs map when no shared codeStore is provided.
7
8
  * ponytail: single-process only; multi-instance → pass ports.codeStore (KV/Redis SET NX EX).
@@ -23,14 +24,9 @@ const memoryCodeStore = {
23
24
  return true;
24
25
  },
25
26
  };
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
27
  /**
32
- * Issue an HMAC-signed auth code.
33
- * Single-use via codeStore, or pruning in-memory Map when omitted.
28
+ * Issue an AES-GCM sealed auth code (v2). Single-use via codeStore, or
29
+ * pruning in-memory Map when omitted.
34
30
  */
35
31
  export const issueAuthCode = async (secret, record, nowMs = Date.now()) => {
36
32
  const body = {
@@ -38,56 +34,52 @@ export const issueAuthCode = async (secret, record, nowMs = Date.now()) => {
38
34
  exp: nowMs + CODE_TTL_MS,
39
35
  jti: randomBase64Url(12),
40
36
  };
41
- const payload = textToBase64Url(JSON.stringify(body));
42
- const sig = await hmacSign(secret, payload);
43
- return `${payload}.${sig}`;
37
+ return `${SEALED_PREFIX}${await seal(secret, "code", body)}`;
38
+ };
39
+ const shapeCheckedRecord = (data, nowMs) => {
40
+ if (typeof data.clientId !== "string" ||
41
+ typeof data.redirectUri !== "string" ||
42
+ typeof data.codeChallenge !== "string" ||
43
+ typeof data.userId !== "string" ||
44
+ typeof data.resource !== "string" ||
45
+ data.resource.length === 0 ||
46
+ typeof data.scope !== "string" ||
47
+ typeof data.exp !== "number" ||
48
+ data.exp < nowMs ||
49
+ typeof data.jti !== "string" ||
50
+ data.jti.length === 0) {
51
+ return null;
52
+ }
53
+ return {
54
+ clientId: data.clientId,
55
+ redirectUri: data.redirectUri,
56
+ codeChallenge: data.codeChallenge,
57
+ userId: data.userId,
58
+ resource: data.resource,
59
+ scope: data.scope,
60
+ exp: data.exp,
61
+ jti: data.jti,
62
+ };
44
63
  };
45
64
  export const consumeAuthCode = async (secret, code, options = {}) => {
46
65
  if (!code || !secret)
47
66
  return null;
48
- const parts = code.split(".");
49
- if (parts.length !== 2)
67
+ // 1.0 dropped v1 (HMAC-only) reading — only `v2.` sealed codes redeem.
68
+ if (!code.startsWith(SEALED_PREFIX))
50
69
  return null;
51
- const [payload, sig] = parts;
52
- if (!payload || !sig)
70
+ const nowMs = options.nowMs ?? Date.now();
71
+ const raw = await unseal(secret, "code", code.slice(SEALED_PREFIX.length));
72
+ if (!raw)
53
73
  return null;
54
- const expected = await hmacSign(secret, payload);
55
- if (!timingSafeEqual(sig, expected))
74
+ const record = shapeCheckedRecord(raw, nowMs);
75
+ if (!record)
56
76
  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 {
77
+ const store = options.codeStore ?? memoryCodeStore;
78
+ const fresh = await store.consume(record.jti, record.exp);
79
+ if (!fresh)
89
80
  return null;
90
- }
81
+ const { jti: _jti, ...rest } = record;
82
+ return rest;
91
83
  };
92
84
  export const newClientId = () => randomBase64Url(16);
93
85
  //# sourceMappingURL=codes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codes.js","sourceRoot":"","sources":["../../src/oauth/codes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codes.js","sourceRoot":"","sources":["../../src/oauth/codes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The consent step between a resolved user and code issuance (RFC 6749
3
+ * §4.1.1 "the resource owner grants or denies the ... request").
4
+ *
5
+ * `/authorize` seals everything the eventual `/consent` POST needs into an
6
+ * opaque, single-use ticket — the ticket carries `clientId`, `redirectUri`,
7
+ * `codeChallenge`, `resource`, and `scope` from the *validated* request, so
8
+ * `handleConsent` trusts nothing from the POST body except which ticket and
9
+ * whether the user approved it. Nothing else in that body is read.
10
+ */
11
+ import type { OAuthUser, RegisteredClient } from "./types.js";
12
+ import { type OAuthRouterOptions } from "./types.js";
13
+ export type ConsentRequest = {
14
+ clientId: string;
15
+ registeredClient: RegisteredClient | null;
16
+ redirectUri: string;
17
+ scope: string[];
18
+ resource: string;
19
+ user: OAuthUser;
20
+ /** Embed this in your form's `consent_ticket` field (hidden input or POST body). */
21
+ ticket: string;
22
+ oauthPath: string;
23
+ };
24
+ export type ConsentOptions = {
25
+ /**
26
+ * Render the approval page yourself. Return any `Response` — HTML, or a
27
+ * redirect to your own route. Omit for the built-in hardened interstitial.
28
+ */
29
+ render?: (input: ConsentRequest) => Response | Promise<Response>;
30
+ /**
31
+ * Client ids that skip approval. Only honored when `clientStore` actually
32
+ * resolves the id — a DCR or self-invented id is never trusted.
33
+ */
34
+ preApprovedClientIds?: string[];
35
+ };
36
+ type ConsentTicketPayload = {
37
+ clientId: string;
38
+ redirectUri: string;
39
+ codeChallenge: string;
40
+ userId: string;
41
+ resource: string;
42
+ scope: string;
43
+ state: string;
44
+ exp: number;
45
+ jti: string;
46
+ };
47
+ export declare const secureRedirect: (location: string) => Response;
48
+ export declare const buildCodeRedirectUrl: (redirectUri: string, code: string, state: string) => string;
49
+ /**
50
+ * RFC 6749 §4.1.2.1 — once `redirect_uri` is trusted, every authorize-time
51
+ * error goes back to the client's own callback, not a bare JSON body the
52
+ * connector never parses. Shared by consent denial (`buildDeniedRedirectUrl`
53
+ * below) and every post-redirect-trust check in `authorize.ts`
54
+ * (`unsupported_response_type`, PKCE, `invalid_scope`, `invalid_target`, …).
55
+ */
56
+ export declare const buildErrorRedirectUrl: (redirectUri: string, error: string, description: string, state: string) => string;
57
+ /** RFC 6749 §4.1.2.1 — denial goes back to the callback, not a bare JSON error. */
58
+ export declare const buildDeniedRedirectUrl: (redirectUri: string, state: string) => string;
59
+ export declare const issueConsentTicket: (secret: string, payload: Omit<ConsentTicketPayload, "exp" | "jti">) => Promise<string>;
60
+ export declare const renderConsent: (options: OAuthRouterOptions, input: ConsentRequest) => Promise<Response>;
61
+ /** Only honored when `clientStore` actually resolves the id — never a self-invented one. */
62
+ export declare const isPreApproved: (options: OAuthRouterOptions, clientId: string, registered: RegisteredClient | null) => boolean;
63
+ export declare const handleConsent: (request: Request, options: OAuthRouterOptions) => Promise<Response>;
64
+ export {};
65
+ //# sourceMappingURL=consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/oauth/consent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,KAAK,kBAAkB,EAA6B,MAAM,YAAY,CAAC;AAKhF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAgBF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,QAQ9C,CAAC;AAEL,eAAO,MAAM,oBAAoB,GAAI,aAAa,MAAM,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAKvF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,EACnB,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,OAAO,MAAM,KACZ,MAMF,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,EAAE,OAAO,MAAM,KAAG,MACF,CAAC;AAE3E,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,MAAM,EACd,SAAS,IAAI,CAAC,oBAAoB,EAAE,KAAK,GAAG,KAAK,CAAC,KACjD,OAAO,CAAC,MAAM,CAKkB,CAAC;AAwDpC,eAAO,MAAM,aAAa,GACxB,SAAS,kBAAkB,EAC3B,OAAO,cAAc,KACpB,OAAO,CAAC,QAAQ,CAA6D,CAAC;AAEjF,4FAA4F;AAC5F,eAAO,MAAM,aAAa,GACxB,SAAS,kBAAkB,EAC3B,UAAU,MAAM,EAChB,YAAY,gBAAgB,GAAG,IAAI,KAClC,OAC0F,CAAC;AAE9F,eAAO,MAAM,aAAa,GACxB,SAAS,OAAO,EAChB,SAAS,kBAAkB,KAC1B,OAAO,CAAC,QAAQ,CA2DlB,CAAC"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The consent step between a resolved user and code issuance (RFC 6749
3
+ * §4.1.1 "the resource owner grants or denies the ... request").
4
+ *
5
+ * `/authorize` seals everything the eventual `/consent` POST needs into an
6
+ * opaque, single-use ticket — the ticket carries `clientId`, `redirectUri`,
7
+ * `codeChallenge`, `resource`, and `scope` from the *validated* request, so
8
+ * `handleConsent` trusts nothing from the POST body except which ticket and
9
+ * whether the user approved it. Nothing else in that body is read.
10
+ */
11
+ import { BodyTooLargeError } from "../body.js";
12
+ import { requireHttpMethod } from "../http.js";
13
+ import { issueAuthCode } from "./codes.js";
14
+ import { OAUTH_ERRORS } from "./constants.js";
15
+ import { readOAuthBody } from "./reqbody.js";
16
+ import { seal, unseal } from "./sealed.js";
17
+ import { oauthError, resolveSecret } from "./types.js";
18
+ const POST_ONLY = new Set(["POST"]);
19
+ const CONSENT_TICKET_TTL_MS = 300_000;
20
+ /** In-memory single-use map, mirroring `codes.ts`'s default when no `codeStore` is configured. */
21
+ const memoryConsumed = new Map();
22
+ const memoryConsentStore = {
23
+ consume: (jti, expMs) => {
24
+ const now = Date.now();
25
+ for (const [key, exp] of memoryConsumed) {
26
+ if (exp < now)
27
+ memoryConsumed.delete(key);
28
+ }
29
+ if (memoryConsumed.has(jti))
30
+ return false;
31
+ memoryConsumed.set(jti, expMs);
32
+ return true;
33
+ },
34
+ };
35
+ export const secureRedirect = (location) => new Response(null, {
36
+ status: 302,
37
+ headers: {
38
+ Location: location,
39
+ "Referrer-Policy": "no-referrer",
40
+ "Cache-Control": "no-store",
41
+ },
42
+ });
43
+ export const buildCodeRedirectUrl = (redirectUri, code, state) => {
44
+ const target = new URL(redirectUri);
45
+ target.searchParams.set("code", code);
46
+ if (state)
47
+ target.searchParams.set("state", state);
48
+ return target.toString();
49
+ };
50
+ /**
51
+ * RFC 6749 §4.1.2.1 — once `redirect_uri` is trusted, every authorize-time
52
+ * error goes back to the client's own callback, not a bare JSON body the
53
+ * connector never parses. Shared by consent denial (`buildDeniedRedirectUrl`
54
+ * below) and every post-redirect-trust check in `authorize.ts`
55
+ * (`unsupported_response_type`, PKCE, `invalid_scope`, `invalid_target`, …).
56
+ */
57
+ export const buildErrorRedirectUrl = (redirectUri, error, description, state) => {
58
+ const target = new URL(redirectUri);
59
+ target.searchParams.set("error", error);
60
+ if (description)
61
+ target.searchParams.set("error_description", description);
62
+ if (state)
63
+ target.searchParams.set("state", state);
64
+ return target.toString();
65
+ };
66
+ /** RFC 6749 §4.1.2.1 — denial goes back to the callback, not a bare JSON error. */
67
+ export const buildDeniedRedirectUrl = (redirectUri, state) => buildErrorRedirectUrl(redirectUri, OAUTH_ERRORS.accessDenied, "", state);
68
+ export const issueConsentTicket = (secret, payload) => seal(secret, "consent", {
69
+ ...payload,
70
+ exp: Date.now() + CONSENT_TICKET_TTL_MS,
71
+ jti: crypto.randomUUID(),
72
+ });
73
+ const ESCAPE_HTML = {
74
+ "&": "&amp;",
75
+ "<": "&lt;",
76
+ ">": "&gt;",
77
+ '"': "&quot;",
78
+ "'": "&#39;",
79
+ };
80
+ const escapeHtml = (value) => value.replace(/[&<>"']/g, (ch) => ESCAPE_HTML[ch] ?? ch);
81
+ const CONSENT_SECURITY_HEADERS = {
82
+ "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; form-action 'self'; frame-ancestors 'none'",
83
+ "X-Frame-Options": "DENY",
84
+ "Referrer-Policy": "no-referrer",
85
+ "Cache-Control": "no-store",
86
+ };
87
+ /** Built-in hardened interstitial — used whenever the host doesn't supply `consent.render`. */
88
+ const renderBuiltInConsent = (input) => {
89
+ const html = `<!doctype html>
90
+ <html lang="en">
91
+ <head>
92
+ <meta charset="utf-8">
93
+ <title>Authorize access</title>
94
+ <style>
95
+ body { font: 16px system-ui, sans-serif; max-width: 32rem; margin: 3rem auto; padding: 0 1rem; }
96
+ dl { display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 1rem; }
97
+ dt { font-weight: 600; }
98
+ button { font-size: 1rem; padding: 0.5rem 1.25rem; margin-right: 0.5rem; }
99
+ </style>
100
+ </head>
101
+ <body>
102
+ <h1>Authorize access</h1>
103
+ <p><strong>${escapeHtml(input.clientId)}</strong> is requesting access to your account.</p>
104
+ <dl>
105
+ <dt>Redirect URI</dt><dd>${escapeHtml(input.redirectUri)}</dd>
106
+ <dt>Scope</dt><dd>${escapeHtml(input.scope.join(" ") || "(none)")}</dd>
107
+ <dt>Resource</dt><dd>${escapeHtml(input.resource)}</dd>
108
+ </dl>
109
+ <form method="POST" action="${escapeHtml(input.oauthPath)}/consent">
110
+ <input type="hidden" name="consent_ticket" value="${escapeHtml(input.ticket)}">
111
+ <button type="submit" name="approved" value="true">Allow</button>
112
+ <button type="submit" name="approved" value="false">Deny</button>
113
+ </form>
114
+ </body>
115
+ </html>`;
116
+ return new Response(html, {
117
+ status: 200,
118
+ headers: { "Content-Type": "text/html; charset=utf-8", ...CONSENT_SECURITY_HEADERS },
119
+ });
120
+ };
121
+ export const renderConsent = async (options, input) => (options.consent?.render ?? renderBuiltInConsent)(input);
122
+ /** Only honored when `clientStore` actually resolves the id — never a self-invented one. */
123
+ export const isPreApproved = (options, clientId, registered) => Boolean(registered) && (options.consent?.preApprovedClientIds?.includes(clientId) ?? false);
124
+ export const handleConsent = async (request, options) => {
125
+ const methodError = requireHttpMethod(request, POST_ONLY, { cors: false });
126
+ if (methodError)
127
+ return methodError;
128
+ let body;
129
+ try {
130
+ body = await readOAuthBody(request);
131
+ }
132
+ catch (exc) {
133
+ if (exc instanceof BodyTooLargeError) {
134
+ return oauthError(OAUTH_ERRORS.invalidRequest, 413, "request body too large");
135
+ }
136
+ return oauthError(OAUTH_ERRORS.invalidRequest, 400, "malformed request body");
137
+ }
138
+ const ticket = body.consent_ticket ?? "";
139
+ if (!ticket) {
140
+ return oauthError(OAUTH_ERRORS.invalidRequest, 400, "consent_ticket required");
141
+ }
142
+ const secret = await resolveSecret(options.ports, request);
143
+ const payload = await unseal(secret, "consent", ticket);
144
+ if (!payload ||
145
+ typeof payload.exp !== "number" ||
146
+ payload.exp < Date.now() ||
147
+ typeof payload.jti !== "string" ||
148
+ !payload.jti) {
149
+ return oauthError(OAUTH_ERRORS.invalidGrant, 400, "invalid or expired consent_ticket");
150
+ }
151
+ const store = options.ports.codeStore ?? memoryConsentStore;
152
+ const fresh = await store.consume(`ct:${payload.jti}`, payload.exp);
153
+ if (!fresh) {
154
+ return oauthError(OAUTH_ERRORS.invalidGrant, 400, "consent_ticket already used");
155
+ }
156
+ const user = await options.ports.resolveUser(request);
157
+ if (!user || user.id !== payload.userId) {
158
+ return oauthError(OAUTH_ERRORS.invalidGrant, 400, "consent_ticket does not match the current user");
159
+ }
160
+ if (body.approved !== "true") {
161
+ return secureRedirect(buildDeniedRedirectUrl(payload.redirectUri, payload.state));
162
+ }
163
+ const code = await issueAuthCode(secret, {
164
+ clientId: payload.clientId,
165
+ redirectUri: payload.redirectUri,
166
+ codeChallenge: payload.codeChallenge,
167
+ userId: user.id,
168
+ resource: payload.resource,
169
+ scope: payload.scope,
170
+ });
171
+ return secureRedirect(buildCodeRedirectUrl(payload.redirectUri, code, payload.state));
172
+ };
173
+ //# sourceMappingURL=consent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/oauth/consent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAA2B,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAuCtC,kGAAkG;AAClG,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AACjD,MAAM,kBAAkB,GAAG;IACzB,OAAO,EAAE,CAAC,GAAW,EAAE,KAAa,EAAW,EAAE;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,cAAc,EAAE,CAAC;YACxC,IAAI,GAAG,GAAG,GAAG;gBAAE,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1C,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAY,EAAE,CAC3D,IAAI,QAAQ,CAAC,IAAI,EAAE;IACjB,MAAM,EAAE,GAAG;IACX,OAAO,EAAE;QACP,QAAQ,EAAE,QAAQ;QAClB,iBAAiB,EAAE,aAAa;QAChC,eAAe,EAAE,UAAU;KAC5B;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,WAAmB,EAAE,IAAY,EAAE,KAAa,EAAU,EAAE;IAC/F,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,KAAK;QAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,WAAmB,EACnB,KAAa,EACb,WAAmB,EACnB,KAAa,EACL,EAAE;IACV,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACxC,IAAI,WAAW;QAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IAC3E,IAAI,KAAK;QAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAmB,EAAE,KAAa,EAAU,EAAE,CACnF,qBAAqB,CAAC,WAAW,EAAE,YAAY,CAAC,YAAY,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,MAAc,EACd,OAAkD,EACjC,EAAE,CACnB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;IACtB,GAAG,OAAO;IACV,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,qBAAqB;IACvC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE;CACM,CAAC,CAAC;AAEpC,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;CACb,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAa,EAAU,EAAE,CAC3C,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAE3D,MAAM,wBAAwB,GAA2B;IACvD,yBAAyB,EACvB,2FAA2F;IAC7F,iBAAiB,EAAE,MAAM;IACzB,iBAAiB,EAAE,aAAa;IAChC,eAAe,EAAE,UAAU;CAC5B,CAAC;AAEF,+FAA+F;AAC/F,MAAM,oBAAoB,GAAG,CAAC,KAAqB,EAAY,EAAE;IAC/D,MAAM,IAAI,GAAG;;;;;;;;;;;;;;aAcF,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;;6BAEV,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;sBACpC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;yBAC1C,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;;8BAErB,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;sDACH,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;;;;;QAKtE,CAAC;IACP,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;QACxB,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,GAAG,wBAAwB,EAAE;KACrF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,OAA2B,EAC3B,KAAqB,EACF,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC;AAEjF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAA2B,EAC3B,QAAgB,EAChB,UAAmC,EAC1B,EAAE,CACX,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,CAAC;AAE9F,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,OAAgB,EAChB,OAA2B,EACR,EAAE;IACrB,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3E,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,IAAI,IAA4B,CAAC;IACjC,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;YACrC,OAAO,UAAU,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,UAAU,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,EAAE,wBAAwB,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,EAAE,yBAAyB,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAuB,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC9E,IACE,CAAC,OAAO;QACR,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;QAC/B,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACxB,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;QAC/B,CAAC,OAAO,CAAC,GAAG,EACZ,CAAC;QACD,OAAO,UAAU,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,EAAE,mCAAmC,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACpE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,UAAU,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,EAAE,6BAA6B,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,UAAU,CACf,YAAY,CAAC,YAAY,EACzB,GAAG,EACH,gDAAgD,CACjD,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC7B,OAAO,cAAc,CAAC,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE;QACvC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IACH,OAAO,cAAc,CAAC,oBAAoB,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACxF,CAAC,CAAC"}
@@ -12,12 +12,16 @@ export declare const OAUTH_ERRORS: {
12
12
  readonly invalidClient: "invalid_client";
13
13
  /** Authorization endpoint — this client may not use this method. RFC 6749 §4.1.2.1. */
14
14
  readonly unauthorizedClient: "unauthorized_client";
15
+ /** Authorization endpoint — `response_type` isn't one this server supports. RFC 6749 §4.1.2.1. */
16
+ readonly unsupportedResponseType: "unsupported_response_type";
15
17
  /** Requested scope exceeds what this server advertises. */
16
18
  readonly invalidScope: "invalid_scope";
17
19
  /** RFC 8707 — requested resource is not acceptable. */
18
20
  readonly invalidTarget: "invalid_target";
19
21
  /** A host port threw. RFC 6749 §4.1.2.1 / §5.2 — our fault, not the client's. */
20
22
  readonly serverError: "server_error";
23
+ /** RFC 6749 §4.1.2.1 — the resource owner denied consent. */
24
+ readonly accessDenied: "access_denied";
21
25
  };
22
26
  export declare const TOKEN_ENDPOINT_AUTH_METHODS: {
23
27
  /** Public client — PKCE is the only proof. */
@@ -1 +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"}
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,kGAAkG;;IAElG,2DAA2D;;IAE3D,uDAAuD;;IAEvD,iFAAiF;;IAEjF,6DAA6D;;CAErD,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"}
@@ -11,12 +11,16 @@ export const OAUTH_ERRORS = {
11
11
  invalidClient: "invalid_client",
12
12
  /** Authorization endpoint — this client may not use this method. RFC 6749 §4.1.2.1. */
13
13
  unauthorizedClient: "unauthorized_client",
14
+ /** Authorization endpoint — `response_type` isn't one this server supports. RFC 6749 §4.1.2.1. */
15
+ unsupportedResponseType: "unsupported_response_type",
14
16
  /** Requested scope exceeds what this server advertises. */
15
17
  invalidScope: "invalid_scope",
16
18
  /** RFC 8707 — requested resource is not acceptable. */
17
19
  invalidTarget: "invalid_target",
18
20
  /** A host port threw. RFC 6749 §4.1.2.1 / §5.2 — our fault, not the client's. */
19
21
  serverError: "server_error",
22
+ /** RFC 6749 §4.1.2.1 — the resource owner denied consent. */
23
+ accessDenied: "access_denied",
20
24
  };
21
25
  export const TOKEN_ENDPOINT_AUTH_METHODS = {
22
26
  /** Public client — PKCE is the only proof. */
@@ -1 +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"}
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,kGAAkG;IAClG,uBAAuB,EAAE,2BAA2B;IACpD,2DAA2D;IAC3D,YAAY,EAAE,eAAe;IAC7B,uDAAuD;IACvD,aAAa,EAAE,gBAAgB;IAC/B,iFAAiF;IACjF,WAAW,EAAE,cAAc;IAC3B,6DAA6D;IAC7D,YAAY,EAAE,eAAe;CACrB,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"}
@@ -26,18 +26,18 @@ export type AuthorizationServerMetadata = {
26
26
  export type MetadataOptions = {
27
27
  origin: string;
28
28
  /** MCP resource path, e.g. "/mcp". */
29
- resourcePath?: string;
29
+ resourcePath?: string | undefined;
30
30
  /** OAuth path prefix, e.g. "/mcp/oauth". */
31
- oauthPath?: string;
31
+ oauthPath?: string | undefined;
32
32
  /** Only advertise grants that are actually handled. */
33
33
  grantTypes: GrantType[];
34
- scopes?: string[];
34
+ scopes?: string[] | undefined;
35
35
  /** Only advertise auth methods the configured clients actually use. */
36
- tokenEndpointAuthMethods?: TokenEndpointAuthMethod[];
36
+ tokenEndpointAuthMethods?: TokenEndpointAuthMethod[] | undefined;
37
37
  /** Advertise `registration_endpoint`. Default true. */
38
- dcrEnabled?: boolean;
38
+ dcrEnabled?: boolean | undefined;
39
39
  /** Advertise `revocation_endpoint`. Default false. */
40
- revocationEnabled?: boolean;
40
+ revocationEnabled?: boolean | undefined;
41
41
  };
42
42
  export declare const protectedResourceMetadata: (options: MetadataOptions) => ProtectedResourceMetadata;
43
43
  export declare const authorizationServerMetadata: (options: MetadataOptions) => AuthorizationServerMetadata;
@@ -1 +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"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAEd,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,GAAG,SAAS,CAAC;IAClC,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,uDAAuD;IACvD,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,uBAAuB,EAAE,GAAG,SAAS,CAAC;IACjE,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,SAAS,eAAe,KAAG,yBAKnE,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"}
@@ -1 +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"}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,2BAA2B,GAE5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AA8CzE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAwB,EAA6B,EAAE,CAAC,CAAC;IACjG,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"}
@@ -1 +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"}
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,CAGnE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,UAAU,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,OAAO,CAIzF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAGjD,CAAC"}
@@ -1,5 +1,5 @@
1
- import { bytesToBase64Url } from "./base64url.js";
2
1
  import { timingSafeEqual } from "../auth/bearer.js";
2
+ import { bytesToBase64Url } from "./base64url.js";
3
3
  export const sha256Base64Url = async (input) => {
4
4
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
5
5
  return bytesToBase64Url(digest);
@@ -1 +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"}
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,KAAa,EAAmB,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,QAAgB,EAAE,SAAiB,EAAoB,EAAE;IAC5F,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"}
@@ -2,7 +2,12 @@ export declare const CLAUDE_CALLBACK = "https://claude.ai/api/mcp/auth_callback"
2
2
  export type RedirectAllowlistOptions = {
3
3
  /** Extra exact-match redirect URIs. */
4
4
  extra?: string[];
5
- /** Allow http(s) loopback hosts — 127.0.0.1, [::1], localhost (any port). Default true. */
5
+ /**
6
+ * Allow `http:` loopback hosts — `127.0.0.1`, `[::1]` (any port). Default
7
+ * true. `localhost` is deliberately not included: RFC 8252 §8.3 — it's
8
+ * DNS-resolvable, so it isn't a loopback guarantee. `https:` is likewise
9
+ * excluded — RFC 8252 native-app loopback redirects are `http:` only.
10
+ */
6
11
  allowLoopback?: boolean;
7
12
  /** Allow the Claude.ai Custom Connector callback. Default true. */
8
13
  allowClaude?: boolean;
@@ -1 +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"}
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;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAuCF,eAAO,MAAM,oBAAoB,GAC/B,KAAK,MAAM,EACX,UAAS,wBAA6B,KACrC,OAGF,CAAC"}
@@ -1,26 +1,39 @@
1
1
  export const CLAUDE_CALLBACK = "https://claude.ai/api/mcp/auth_callback";
2
2
  const isClaudeCallback = (uri, options) => options.allowClaude !== false && uri === CLAUDE_CALLBACK;
3
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"]);
4
+ /**
5
+ * WHATWG URL keeps IPv6 hosts bracketed, so `[::1]` is the parsed hostname.
6
+ * `http://127.1/cb` and `http://2130706433/cb` normalize to `127.0.0.1` here
7
+ * and are genuinely loopback; `0.0.0.0` is not, and is deliberately absent.
8
+ */
9
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "[::1]"]);
6
10
  const isLoopbackHttp = (uri, options) => {
7
11
  if (options.allowLoopback === false)
8
12
  return false;
9
13
  try {
10
14
  const parsed = new URL(uri);
11
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
15
+ if (parsed.protocol !== "http:")
12
16
  return false;
13
- }
14
17
  return LOOPBACK_HOSTS.has(parsed.hostname);
15
18
  }
16
19
  catch {
17
20
  return false;
18
21
  }
19
22
  };
20
- const REDIRECT_PREDICATES = [
21
- isClaudeCallback,
22
- isExtraAllowed,
23
- isLoopbackHttp,
24
- ];
25
- export const isAllowedRedirectUri = (uri, options = {}) => REDIRECT_PREDICATES.some((predicate) => predicate(uri, options));
23
+ const REDIRECT_PREDICATES = [isClaudeCallback, isExtraAllowed, isLoopbackHttp];
24
+ /** RFC 6749 forbids a fragment in redirect_uri; embedded credentials are never legitimate. */
25
+ const carriesFragmentOrCredentials = (uri) => {
26
+ try {
27
+ const parsed = new URL(uri);
28
+ return parsed.hash !== "" || parsed.username !== "" || parsed.password !== "";
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ };
34
+ export const isAllowedRedirectUri = (uri, options = {}) => {
35
+ if (carriesFragmentOrCredentials(uri))
36
+ return false;
37
+ return REDIRECT_PREDICATES.some((predicate) => predicate(uri, options));
38
+ };
26
39
  //# sourceMappingURL=redirect.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"redirect.js","sourceRoot":"","sources":["../../src/oauth/redirect.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,yCAAyC,CAAC;AAkBzE,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,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAElG;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD,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;YAAE,OAAO,KAAK,CAAC;QAC9C,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,CAAC,gBAAgB,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;AAEpG,8FAA8F;AAC9F,MAAM,4BAA4B,GAAG,CAAC,GAAW,EAAW,EAAE;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,IAAI,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,GAAW,EACX,UAAoC,EAAE,EAC7B,EAAE;IACX,IAAI,4BAA4B,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1E,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared JSON/form body reader for `/token` and `/revoke`. `/token` has
3
+ * always accepted both; `/revoke` used to parse form-only, so a client that
4
+ * revoked with `Content-Type: application/json` (matching how it likely
5
+ * called `/token`) got a silent `invalid_request "token required"` — the
6
+ * caller believes the token is dead when the request was never understood.
7
+ */
8
+ /** JSON when `Content-Type` says so; form-encoded otherwise (the RFC 6749 default). */
9
+ export declare const readOAuthBody: (request: Request) => Promise<Record<string, string>>;
10
+ //# sourceMappingURL=reqbody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reqbody.d.ts","sourceRoot":"","sources":["../../src/oauth/reqbody.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuBH,uFAAuF;AACvF,eAAO,MAAM,aAAa,GAAU,SAAS,OAAO,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGpF,CAAC"}