@arnaudjnn/billing-tools 0.15.0 → 0.17.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 (48) hide show
  1. package/README.md +37 -0
  2. package/dist/adapters/workos-org.d.ts +5 -0
  3. package/dist/adapters/workos-org.d.ts.map +1 -1
  4. package/dist/adapters/workos-org.js +27 -0
  5. package/dist/adapters/workos-org.js.map +1 -1
  6. package/dist/agent-auth/index.d.ts +3 -2
  7. package/dist/agent-auth/index.d.ts.map +1 -1
  8. package/dist/agent-auth/index.js +11 -2
  9. package/dist/agent-auth/index.js.map +1 -1
  10. package/dist/auth.d.ts +1 -0
  11. package/dist/auth.d.ts.map +1 -1
  12. package/dist/auth.js +1 -1
  13. package/dist/auth.js.map +1 -1
  14. package/dist/billing.d.ts +11 -1
  15. package/dist/billing.d.ts.map +1 -1
  16. package/dist/billing.js +31 -1
  17. package/dist/billing.js.map +1 -1
  18. package/dist/create-billing.d.ts +17 -0
  19. package/dist/create-billing.d.ts.map +1 -1
  20. package/dist/create-billing.js +52 -2
  21. package/dist/create-billing.js.map +1 -1
  22. package/dist/index.d.ts +5 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +11 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/metering.d.ts +38 -0
  27. package/dist/metering.d.ts.map +1 -0
  28. package/dist/metering.js +58 -0
  29. package/dist/metering.js.map +1 -0
  30. package/dist/oauth-proxy/index.d.ts +51 -0
  31. package/dist/oauth-proxy/index.d.ts.map +1 -0
  32. package/dist/oauth-proxy/index.js +385 -0
  33. package/dist/oauth-proxy/index.js.map +1 -0
  34. package/dist/plans.d.ts +44 -4
  35. package/dist/plans.d.ts.map +1 -1
  36. package/dist/plans.js +65 -11
  37. package/dist/plans.js.map +1 -1
  38. package/dist/sync.d.ts.map +1 -1
  39. package/dist/sync.js +27 -4
  40. package/dist/sync.js.map +1 -1
  41. package/dist/topup.d.ts +43 -0
  42. package/dist/topup.d.ts.map +1 -0
  43. package/dist/topup.js +80 -0
  44. package/dist/topup.js.map +1 -0
  45. package/dist/types.d.ts +6 -0
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/types.js.map +1 -1
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,9 +3,15 @@ export { resolveConfig, internalDomainsFromEnv } from "./types.js";
3
3
  // Auth engine
4
4
  export { authContext, runWithAuth, runWithResolvedOrg, enforceAccess, enforceTokens, } from "./auth.js";
5
5
  // Billing engine (Stripe math)
6
- export { getStripe, stripeConfigured, ensureStripeCustomer, getBillingCustomerId, getTokenBalance, deductTokens, creditTokens, createTokenCheckoutSession, createBillingPortalSession, getAutoReloadSettings, setAutoReloadSettings, tryAutoReload, listInvoices, listSubscriptionPrices, resolveSubscriptionPrice, } from "./billing.js";
6
+ export { getStripe, stripeConfigured, ensureStripeCustomer, getBillingCustomerId, getTokenBalance, deductTokens, creditTokens, usageSince, createTokenCheckoutSession, createBillingPortalSession, getAutoReloadSettings, setAutoReloadSettings, tryAutoReload, listInvoices, listSubscriptionPrices, resolveSubscriptionPrice, } from "./billing.js";
7
7
  // Declarative plans (auto-provision Stripe products/prices from config)
8
- export { ensurePlans, planPriceId, planForPriceId, seatLimit, includedTokens, lookupKeyFor, } from "./plans.js";
8
+ export { ensurePlans, planPriceId, planForPriceId, seatTypeForPriceId, seatLimit, includedTokens, includedTokensByType, lookupKeyFor, DEFAULT_SEAT_TYPES, } from "./plans.js";
9
+ // Per-execution metering engine (prepaid balance; per-seat packs or a global
10
+ // pool; usage summed from Stripe balance-transaction metadata — no new backend).
11
+ export { meterUsage, } from "./metering.js";
12
+ // Top-up requests (user → owner approval) + admin-gated auto-top-up. Stored in
13
+ // WorkOS org metadata via the adapter — no new backend.
14
+ export { requestTopUp, listTopUpRequests, approveTopUp, denyTopUp, extraAllowance, setAutoTopUp, } from "./topup.js";
9
15
  // WorkOS magic-auth
10
16
  export { sendMagicAuth, verifyMagicAuth } from "./magic-auth.js";
11
17
  // WorkOS organization invitations (shared, hook-configurable)
@@ -27,6 +33,9 @@ export { createAgentAuth, CLAIM_GRANT_TYPE, } from "./agent-auth/index.js";
27
33
  export { inMemoryClaimStore, } from "./agent-auth/claim-store.js";
28
34
  // Machine payments — MPP (the 402 payment sibling of auth.md)
29
35
  export { createMachinePaymentHandler, createPaymentMd, } from "./machine-payment/index.js";
36
+ // MCP OAuth 2.1 + Dynamic Client Registration proxy (opt-in via
37
+ // createBilling({ oauthProxy }) or standalone).
38
+ export { createOAuthProxy, } from "./oauth-proxy/index.js";
30
39
  // Next route factories
31
40
  export { createToolListHandler, createToolDispatchHandler } from "./routes/rest.js";
32
41
  export { createMcpTransport } from "./routes/mcp.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAYnE,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEnE,cAAc;AACd,OAAO,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,+BAA+B;AAC/B,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,wBAAwB,GAEzB,MAAM,cAAc,CAAC;AAEtB,wEAAwE;AACxE,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,SAAS,EACT,cAAc,EACd,YAAY,GAKb,MAAM,YAAY,CAAC;AAEpB,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjE,8DAA8D;AAC9D,OAAO,EACL,uBAAuB,GAMxB,MAAM,kBAAkB,CAAC;AAE1B,sEAAsE;AACtE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAmB,MAAM,aAAa,CAAC;AAElF,+EAA+E;AAC/E,OAAO,EACL,iBAAiB,EACjB,eAAe,GAIhB,MAAM,WAAW,CAAC;AAEnB,4EAA4E;AAC5E,OAAO,EACL,YAAY,GAKb,MAAM,aAAa,CAAC;AAErB,oBAAoB;AACpB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAE7B,uBAAuB;AACvB,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAmB,MAAM,eAAe,CAAC;AAEvF,oEAAoE;AACpE,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAE/E,2EAA2E;AAC3E,OAAO,EACL,eAAe,EACf,gBAAgB,GAMjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,GAInB,MAAM,6BAA6B,CAAC;AAErC,8DAA8D;AAC9D,OAAO,EACL,2BAA2B,EAC3B,eAAe,GAMhB,MAAM,4BAA4B,CAAC;AAEpC,uBAAuB;AACvB,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAmB,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,kBAAkB,EAA4B,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAuB,MAAM,qBAAqB,CAAC;AAEtF,cAAc;AACd,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAwB,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAGL,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,QAAQ;AACR,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAYnE,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEnE,cAAc;AACd,OAAO,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,+BAA+B;AAC/B,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,wBAAwB,GAEzB,MAAM,cAAc,CAAC;AAEtB,wEAAwE;AACxE,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,GAMnB,MAAM,YAAY,CAAC;AAEpB,6EAA6E;AAC7E,iFAAiF;AACjF,OAAO,EACL,UAAU,GAIX,MAAM,eAAe,CAAC;AAEvB,+EAA+E;AAC/E,wDAAwD;AACxD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,cAAc,EACd,YAAY,GAEb,MAAM,YAAY,CAAC;AAEpB,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjE,8DAA8D;AAC9D,OAAO,EACL,uBAAuB,GAMxB,MAAM,kBAAkB,CAAC;AAE1B,sEAAsE;AACtE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAmB,MAAM,aAAa,CAAC;AAElF,+EAA+E;AAC/E,OAAO,EACL,iBAAiB,EACjB,eAAe,GAIhB,MAAM,WAAW,CAAC;AAEnB,4EAA4E;AAC5E,OAAO,EACL,YAAY,GAKb,MAAM,aAAa,CAAC;AAErB,oBAAoB;AACpB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC;AAE7B,uBAAuB;AACvB,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAmB,MAAM,eAAe,CAAC;AAEvF,oEAAoE;AACpE,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAE/E,2EAA2E;AAC3E,OAAO,EACL,eAAe,EACf,gBAAgB,GAMjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,GAInB,MAAM,6BAA6B,CAAC;AAErC,8DAA8D;AAC9D,OAAO,EACL,2BAA2B,EAC3B,eAAe,GAMhB,MAAM,4BAA4B,CAAC;AAEpC,gEAAgE;AAChE,gDAAgD;AAChD,OAAO,EACL,gBAAgB,GAKjB,MAAM,wBAAwB,CAAC;AAEhC,uBAAuB;AACvB,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAmB,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,kBAAkB,EAA4B,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAuB,MAAM,qBAAqB,CAAC;AAEtF,cAAc;AACd,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAwB,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAGL,UAAU,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,QAAQ;AACR,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { PlansConfig } from "./plans.js";
2
+ import type { BillingAdapter, ResolvedConfig } from "./types.js";
3
+ export interface MeterCaller {
4
+ /** `user` = a human via session/OAuth (their seat); `api` = an API key / agent
5
+ * (the shared API seat). Decides which pack the execution draws — the surface
6
+ * (ui/api/mcp/cli) is irrelevant. */
7
+ kind: "user" | "api";
8
+ /** WorkOS member id (user) or API key id (api) — for per-caller attribution. */
9
+ id?: string;
10
+ /** The caller's seat type, resolved by the consumer (e.g. `standard`,
11
+ * `premium`, `api`). Used for the per-seat pack cap in `per_seat` plans. */
12
+ seatType?: string;
13
+ }
14
+ export interface MeterInput {
15
+ orgId: string;
16
+ action: string;
17
+ /** Token cost for this execution (rate card × units), resolved by the consumer. */
18
+ cost: number;
19
+ plans: PlansConfig;
20
+ /** The org's current plan key (consumer resolves + caches it). */
21
+ plan: string | null;
22
+ /** Start of the current billing cycle, unix seconds — the window for per-seat
23
+ * usage. */
24
+ cycleStart: number;
25
+ /** Approved extra allowance for this caller this cycle (owner-granted top-up),
26
+ * added on top of the seat pack. Consumer resolves it via `extraAllowance`. */
27
+ extraAllowance?: number;
28
+ caller?: MeterCaller;
29
+ }
30
+ export type MeterResult = {
31
+ ok: true;
32
+ } | {
33
+ ok: false;
34
+ reason: "no_billing" | "insufficient_balance" | "seat_allowance_reached";
35
+ message: string;
36
+ };
37
+ export declare function meterUsage(adapter: BillingAdapter, config: ResolvedConfig, input: MeterInput): Promise<MeterResult>;
38
+ //# sourceMappingURL=metering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../src/metering.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B;;0CAEsC;IACtC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,gFAAgF;IAChF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;iFAC6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,kEAAkE;IAClE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;iBACa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB;oFACgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IACE,EAAE,EAAE,KAAK,CAAA;IACT,MAAM,EAAE,YAAY,GAAG,sBAAsB,GAAG,wBAAwB,CAAA;IACxE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAUL,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,WAAW,CAAC,CA0DtB"}
@@ -0,0 +1,58 @@
1
+ import { deductTokens, getBillingCustomerId, getTokenBalance, stripeConfigured, tryAutoReload, usageSince, } from "./billing.js";
2
+ import { isInternalOrg } from "./auth.js";
3
+ // The shared metering engine (used by every consumer). Pricing is per execution
4
+ // at a uniform cost regardless of surface. The org's prepaid Stripe balance is
5
+ // the shared reserve; in `per_seat` plans each caller's per-cycle pack caps how
6
+ // much of it they may spend (usage summed from Stripe balance-transaction
7
+ // metadata — no separate ledger), while `global` plans (e.g. an Enterprise token
8
+ // commitment) impose no per-seat cap. The debit is tagged with the caller so
9
+ // usage is attributable. Free (cost 0), Stripe-unset, and internal orgs pass
10
+ // through untouched. Persistence is entirely Stripe + the adapter — no new DB.
11
+ export async function meterUsage(adapter, config, input) {
12
+ const { orgId, action, cost, plans, plan, cycleStart, caller } = input;
13
+ const extra = input.extraAllowance ?? 0;
14
+ if (cost <= 0)
15
+ return { ok: true };
16
+ if (!stripeConfigured())
17
+ return { ok: true };
18
+ if (await isInternalOrg(adapter, orgId, config.internalDomains))
19
+ return { ok: true };
20
+ const customerId = await getBillingCustomerId(adapter, orgId);
21
+ if (!customerId) {
22
+ return { ok: false, reason: "no_billing", message: "No billing account found." };
23
+ }
24
+ // The shared reserve must cover the debit (it funds every pack + any API top-up).
25
+ const balance = await getTokenBalance(customerId);
26
+ if (balance < cost) {
27
+ return {
28
+ ok: false,
29
+ reason: "insufficient_balance",
30
+ message: `Insufficient tokens: this costs ${cost} but the workspace has ${balance}. Top up to continue.`,
31
+ };
32
+ }
33
+ // Per-seat allowance cap — only for `per_seat` plans with a seat context.
34
+ // `global` plans (Enterprise commitment) have no per-seat cap.
35
+ const planDef = plan ? plans[plan] : undefined;
36
+ const mode = planDef?.allowanceMode ?? "per_seat";
37
+ if (mode === "per_seat" && caller?.seatType) {
38
+ const pack = planDef?.seatTypes?.[caller.seatType]?.includedTokens;
39
+ if (pack != null) {
40
+ const used = await usageSince(customerId, cycleStart, caller.kind === "api"
41
+ ? { callerKind: "api" }
42
+ : { callerKind: "user", callerId: caller.id });
43
+ if (used + cost > pack + extra && caller.kind === "user") {
44
+ // Hard cap for a user seat. (API seat over its pack is allowed — it
45
+ // draws the shared reserve, which is the API pool's top-up.)
46
+ return {
47
+ ok: false,
48
+ reason: "seat_allowance_reached",
49
+ message: "Seat token allowance reached for this cycle. Request extra from the workspace owner.",
50
+ };
51
+ }
52
+ }
53
+ }
54
+ await deductTokens(customerId, action, cost, config.currency, caller ? { kind: caller.kind, id: caller.id } : undefined);
55
+ tryAutoReload(customerId, config.currency).catch(() => { });
56
+ return { ok: true };
57
+ }
58
+ //# sourceMappingURL=metering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metering.js","sourceRoot":"","sources":["../src/metering.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ export interface ClaimGrantChain {
2
+ type: string;
3
+ handle: (params: Record<string, string>) => Promise<Response> | Response;
4
+ }
5
+ export interface OAuthProxyPaths {
6
+ authorize?: string;
7
+ register?: string;
8
+ callback?: string;
9
+ }
10
+ export interface OAuthProxyOptions {
11
+ /** Absolute base URL for the AuthKit redirect_uri + advertised endpoints.
12
+ * String, per-request resolver, or omitted to derive from forwarded headers. */
13
+ baseUrl?: string | ((request: Request) => string);
14
+ /** WorkOS client id. Defaults to process.env.WORKOS_CLIENT_ID. */
15
+ workosClientId?: string;
16
+ /** HS256 key for the proxy's refresh tokens. Defaults to
17
+ * process.env.REFRESH_TOKEN_SECRET. No fallback — see the note above. */
18
+ refreshSecret?: string;
19
+ paths?: OAuthProxyPaths;
20
+ /** Seconds/ms overrides. accessTokenTtl is what we *advertise* for the WorkOS
21
+ * access token; refreshTtl is how long our wrapper JWT stays valid. */
22
+ ttl?: {
23
+ clientMs?: number;
24
+ sessionMs?: number;
25
+ codeMs?: number;
26
+ accessTokenSeconds?: number;
27
+ refreshSeconds?: number;
28
+ };
29
+ /** Chain another grant type through the same /oauth/token route — e.g.
30
+ * auth.md's claim grant, so one route serves both. Pass a function when the
31
+ * handler isn't available yet at construction (createBilling builds the proxy
32
+ * first, because agent-auth needs its endpoints for discovery). */
33
+ claimGrant?: ClaimGrantChain | (() => ClaimGrantChain | undefined);
34
+ }
35
+ export declare function createOAuthProxy(opts?: OAuthProxyOptions): {
36
+ register: (request: Request) => Promise<Response>;
37
+ authorize: (request: Request) => Promise<Response>;
38
+ callback: (request: Request) => Promise<Response>;
39
+ token: (request: Request) => Promise<Response>;
40
+ /** Grant types to advertise in AS metadata. */
41
+ grantTypes: readonly ["authorization_code", "refresh_token"];
42
+ /** AS-metadata fields this proxy adds — merge into the discovery document so
43
+ * the endpoints are only advertised where they actually exist. */
44
+ asMetadata: (request: Request) => {
45
+ authorization_endpoint: string;
46
+ registration_endpoint: string;
47
+ };
48
+ paths: Required<OAuthProxyPaths>;
49
+ };
50
+ export type OAuthProxy = ReturnType<typeof createOAuthProxy>;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth-proxy/index.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC;qFACiF;IACjF,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC;IAClD,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;4EACwE;IACxE,GAAG,CAAC,EAAE;QACJ,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;wEAGoE;IACpE,UAAU,CAAC,EAAE,eAAe,GAAG,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,CAAC;CACpE;AAsDD,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,iBAAsB;wBAwF1B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;yBAyC1B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;wBAwC5B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;qBA0I9B,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;IAmBvD,+CAA+C;;IAE/C;uEACmE;0BAC7C,OAAO;;;;;EAMhC;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,385 @@
1
+ // MCP OAuth 2.1 proxy: lets a *dynamic* client (Claude Desktop, Claude.ai, any
2
+ // MCP client that speaks RFC 7591 Dynamic Client Registration) connect to a
3
+ // remote MCP server without a human pasting an API key.
4
+ //
5
+ // It is a proxy, not an authorization server: the user actually authenticates
6
+ // with WorkOS AuthKit, and we translate that into the OAuth shape MCP clients
7
+ // expect. Four endpoints, all framework-agnostic (Request → Response):
8
+ //
9
+ // POST /oauth/register RFC 7591 — client registers, gets a client_id
10
+ // GET /oauth/authorize parks the client's request, redirects to AuthKit
11
+ // GET /oauth/callback AuthKit returns; we mint OUR code, bounce to the client
12
+ // POST /oauth/token code → {access_token, refresh_token}; also refreshes
13
+ //
14
+ // The access token handed back is the WorkOS access token (short-lived, ~10 min).
15
+ // The refresh token is OUR HS256 JWT wrapping the WorkOS refresh token, so the
16
+ // client never holds WorkOS credentials directly and we can bind the token to
17
+ // the client_id that obtained it.
18
+ //
19
+ // Why this lives here and not in an app: it is pure protocol plumbing with one
20
+ // product-specific input (the WorkOS project). Two consumers already needed it,
21
+ // and the second one copying the first is how the fallback-secret bug below got
22
+ // duplicated in the first place.
23
+ //
24
+ // SECURITY — the refresh secret is REQUIRED. An earlier app-local version fell
25
+ // back to `WORKOS_CLIENT_ID`, which is a *public* OAuth identifier that appears
26
+ // in authorize URLs and discovery documents, so anyone who knew it could forge a
27
+ // 30-day refresh token. There is deliberately no fallback here: without
28
+ // REFRESH_TOKEN_SECRET the token endpoint returns server_error rather than
29
+ // signing with something guessable.
30
+ import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
31
+ import { getWorkOS } from "../workos.js";
32
+ const b64url = (b) => b.toString("base64url");
33
+ function jsonError(error, description, status = 400) {
34
+ return Response.json({ error, error_description: description }, { status });
35
+ }
36
+ function baseUrlFromRequest(request) {
37
+ const h = request.headers;
38
+ const host = h.get("x-forwarded-host") ?? h.get("host");
39
+ const proto = h.get("x-forwarded-proto") ?? (host?.startsWith("localhost") ? "http" : "https");
40
+ if (host)
41
+ return `${proto}://${host}`;
42
+ return new URL(request.url).origin;
43
+ }
44
+ /** RFC 7636. `plain` is accepted because the MCP spec still allows it, but S256
45
+ * is what every real client sends. */
46
+ function verifyCodeChallenge(verifier, challenge, method) {
47
+ if (method === "plain")
48
+ return verifier === challenge;
49
+ if (method === "S256")
50
+ return createHash("sha256").update(verifier).digest("base64url") === challenge;
51
+ return false;
52
+ }
53
+ export function createOAuthProxy(opts = {}) {
54
+ const paths = {
55
+ authorize: opts.paths?.authorize ?? "/oauth/authorize",
56
+ register: opts.paths?.register ?? "/oauth/register",
57
+ callback: opts.paths?.callback ?? "/oauth/callback",
58
+ };
59
+ const CLIENT_TTL = opts.ttl?.clientMs ?? 24 * 60 * 60 * 1000;
60
+ const SESSION_TTL = opts.ttl?.sessionMs ?? 10 * 60 * 1000;
61
+ const CODE_TTL = opts.ttl?.codeMs ?? 5 * 60 * 1000;
62
+ const ACCESS_TTL = opts.ttl?.accessTokenSeconds ?? 600;
63
+ const REFRESH_TTL = opts.ttl?.refreshSeconds ?? 30 * 24 * 60 * 60;
64
+ // In-memory, single-process — same assumption as the default claim store.
65
+ // Pruned on access rather than on a timer, so there is no dangling interval in
66
+ // a serverless/edge build.
67
+ const clients = new Map();
68
+ const sessions = new Map();
69
+ const codes = new Map();
70
+ function prune() {
71
+ const now = Date.now();
72
+ for (const [k, v] of clients)
73
+ if (now - v.created_at > CLIENT_TTL)
74
+ clients.delete(k);
75
+ for (const [k, v] of sessions)
76
+ if (now - v.created_at > SESSION_TTL)
77
+ sessions.delete(k);
78
+ for (const [k, v] of codes)
79
+ if (now - v.created_at > CODE_TTL)
80
+ codes.delete(k);
81
+ }
82
+ const baseUrlOf = (request) => typeof opts.baseUrl === "function"
83
+ ? opts.baseUrl(request)
84
+ : (opts.baseUrl ?? baseUrlFromRequest(request));
85
+ const workosClientId = () => opts.workosClientId ?? process.env.WORKOS_CLIENT_ID;
86
+ /** Throws when unset — callers turn that into a 500 rather than signing with
87
+ * a guessable key. Read lazily so app boot never depends on it. */
88
+ function refreshKey() {
89
+ const s = opts.refreshSecret ?? process.env.REFRESH_TOKEN_SECRET;
90
+ if (!s) {
91
+ throw new Error("REFRESH_TOKEN_SECRET is not configured — the OAuth proxy refuses to sign refresh tokens without it");
92
+ }
93
+ return Buffer.from(s, "utf8");
94
+ }
95
+ // HS256 JWT by hand: `jose` would be a dependency for ~15 lines, and the
96
+ // format is wire-compatible with it (same header, same claims), so tokens
97
+ // minted by an app's previous jose-based implementation still verify here.
98
+ function signRefresh(workosRefreshToken, clientId) {
99
+ const now = Math.floor(Date.now() / 1000);
100
+ const header = b64url(Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })));
101
+ const payload = b64url(Buffer.from(JSON.stringify({ wrt: workosRefreshToken, cid: clientId, iat: now, exp: now + REFRESH_TTL })));
102
+ const sig = b64url(createHmac("sha256", refreshKey()).update(`${header}.${payload}`).digest());
103
+ return `${header}.${payload}.${sig}`;
104
+ }
105
+ /** Throws if the secret is missing (a 500 condition), returns null for a token
106
+ * that is simply invalid (a 400 condition). Conflating the two sent
107
+ * "invalid_grant" to a client whose token was fine while WE were misconfigured. */
108
+ function verifyRefresh(token) {
109
+ const expected = (() => {
110
+ const parts = token.split(".");
111
+ if (parts.length !== 3)
112
+ return null;
113
+ return createHmac("sha256", refreshKey()).update(`${parts[0]}.${parts[1]}`).digest();
114
+ })();
115
+ if (!expected)
116
+ return null;
117
+ const parts = token.split(".");
118
+ const [, payload, sig] = parts;
119
+ const given = Buffer.from(sig, "base64url");
120
+ if (given.length !== expected.length || !timingSafeEqual(given, expected))
121
+ return null;
122
+ try {
123
+ const claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
124
+ if (!claims.wrt || !claims.cid)
125
+ return null;
126
+ if (claims.exp && Math.floor(Date.now() / 1000) >= claims.exp)
127
+ return null;
128
+ return { workosRefreshToken: claims.wrt, clientId: claims.cid };
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
134
+ /** RFC 7591 dynamic client registration. Public clients only
135
+ * (token_endpoint_auth_method: none) — PKCE is what protects the exchange. */
136
+ async function register(request) {
137
+ prune();
138
+ let body;
139
+ try {
140
+ body = (await request.json());
141
+ }
142
+ catch {
143
+ return jsonError("invalid_client_metadata", "Invalid JSON body");
144
+ }
145
+ const uris = body.redirect_uris;
146
+ if (!Array.isArray(uris) || uris.length === 0) {
147
+ return jsonError("invalid_client_metadata", "redirect_uris is required and must be a non-empty array");
148
+ }
149
+ if (!uris.every((u) => typeof u === "string")) {
150
+ return jsonError("invalid_client_metadata", "Each redirect_uri must be a string");
151
+ }
152
+ const client = {
153
+ client_id: randomUUID(),
154
+ client_name: typeof body.client_name === "string" ? body.client_name : undefined,
155
+ redirect_uris: uris,
156
+ grant_types: ["authorization_code", "refresh_token"],
157
+ response_types: ["code"],
158
+ token_endpoint_auth_method: "none",
159
+ created_at: Date.now(),
160
+ };
161
+ clients.set(client.client_id, client);
162
+ return Response.json({
163
+ client_id: client.client_id,
164
+ client_name: client.client_name,
165
+ redirect_uris: client.redirect_uris,
166
+ grant_types: client.grant_types,
167
+ response_types: client.response_types,
168
+ token_endpoint_auth_method: client.token_endpoint_auth_method,
169
+ }, { status: 201 });
170
+ }
171
+ /** Parks the client's request under a session id, then hands the user to
172
+ * AuthKit. The session id travels as WorkOS's `state`, so the callback can
173
+ * match the returning user back to the waiting client. */
174
+ async function authorize(request) {
175
+ prune();
176
+ const q = new URL(request.url).searchParams;
177
+ const clientId = q.get("client_id");
178
+ const redirectUri = q.get("redirect_uri");
179
+ if (!clientId || !redirectUri || q.get("response_type") !== "code") {
180
+ return jsonError("invalid_request", "Missing or invalid required parameters (client_id, redirect_uri, response_type=code)");
181
+ }
182
+ const client = clients.get(clientId);
183
+ if (!client)
184
+ return jsonError("invalid_client", "Unknown client_id");
185
+ if (!client.redirect_uris.includes(redirectUri)) {
186
+ return jsonError("invalid_request", "redirect_uri does not match registered URIs");
187
+ }
188
+ const wosClientId = workosClientId();
189
+ if (!wosClientId)
190
+ return jsonError("server_error", "WORKOS_CLIENT_ID is not configured", 500);
191
+ const sessionId = randomUUID();
192
+ sessions.set(sessionId, {
193
+ client_id: clientId,
194
+ redirect_uri: redirectUri,
195
+ state: q.get("state") ?? undefined,
196
+ code_challenge: q.get("code_challenge") ?? undefined,
197
+ code_challenge_method: q.get("code_challenge_method") ?? undefined,
198
+ created_at: Date.now(),
199
+ });
200
+ const url = new URL("https://api.workos.com/user_management/authorize");
201
+ url.searchParams.set("client_id", wosClientId);
202
+ url.searchParams.set("redirect_uri", `${baseUrlOf(request)}${paths.callback}`);
203
+ url.searchParams.set("response_type", "code");
204
+ url.searchParams.set("provider", "authkit");
205
+ url.searchParams.set("state", sessionId);
206
+ return Response.redirect(url.toString(), 302);
207
+ }
208
+ /** AuthKit's redirect target. Exchanges WorkOS's code for tokens, mints OUR
209
+ * single-use code, and bounces back to the client's redirect_uri. */
210
+ async function callback(request) {
211
+ prune();
212
+ const q = new URL(request.url).searchParams;
213
+ const workosCode = q.get("code");
214
+ const sessionId = q.get("state");
215
+ if (!workosCode || !sessionId)
216
+ return jsonError("invalid_request", "Missing code or state parameter");
217
+ const session = sessions.get(sessionId);
218
+ if (!session)
219
+ return jsonError("invalid_request", "Invalid or expired session");
220
+ sessions.delete(sessionId);
221
+ const wosClientId = workosClientId();
222
+ if (!wosClientId)
223
+ return jsonError("server_error", "WORKOS_CLIENT_ID is not configured", 500);
224
+ let accessToken;
225
+ let refreshToken;
226
+ try {
227
+ const auth = await getWorkOS().userManagement.authenticateWithCode({
228
+ clientId: wosClientId,
229
+ code: workosCode,
230
+ });
231
+ accessToken = auth.accessToken;
232
+ refreshToken = auth.refreshToken;
233
+ }
234
+ catch (e) {
235
+ console.error("[oauth-proxy] WorkOS code exchange failed:", e);
236
+ return jsonError("server_error", "Failed to exchange authorization code with WorkOS", 500);
237
+ }
238
+ const code = randomUUID();
239
+ codes.set(code, {
240
+ client_id: session.client_id,
241
+ redirect_uri: session.redirect_uri,
242
+ access_token: accessToken,
243
+ refresh_token: refreshToken,
244
+ code_challenge: session.code_challenge,
245
+ code_challenge_method: session.code_challenge_method,
246
+ used: false,
247
+ created_at: Date.now(),
248
+ });
249
+ const back = new URL(session.redirect_uri);
250
+ back.searchParams.set("code", code);
251
+ if (session.state)
252
+ back.searchParams.set("state", session.state);
253
+ return Response.redirect(back.toString(), 302);
254
+ }
255
+ async function handleAuthorizationCode(params) {
256
+ const { code, client_id, redirect_uri, code_verifier } = params;
257
+ if (!code || !client_id) {
258
+ return jsonError("invalid_request", "Missing required parameters (code, client_id)");
259
+ }
260
+ const entry = codes.get(code);
261
+ if (!entry)
262
+ return jsonError("invalid_grant", "Invalid or expired authorization code");
263
+ if (entry.used) {
264
+ // Replay: burn it. RFC 6749 §4.1.2 — a reused code must invalidate.
265
+ codes.delete(code);
266
+ return jsonError("invalid_grant", "Authorization code has already been used");
267
+ }
268
+ if (entry.client_id !== client_id)
269
+ return jsonError("invalid_grant", "client_id does not match");
270
+ if (redirect_uri && entry.redirect_uri !== redirect_uri) {
271
+ return jsonError("invalid_grant", "redirect_uri does not match");
272
+ }
273
+ if (entry.code_challenge && entry.code_challenge_method) {
274
+ if (!code_verifier)
275
+ return jsonError("invalid_request", "code_verifier is required for PKCE");
276
+ if (!verifyCodeChallenge(code_verifier, entry.code_challenge, entry.code_challenge_method)) {
277
+ return jsonError("invalid_grant", "PKCE code_verifier verification failed");
278
+ }
279
+ }
280
+ entry.used = true;
281
+ let refresh;
282
+ try {
283
+ refresh = signRefresh(entry.refresh_token, entry.client_id);
284
+ }
285
+ catch (e) {
286
+ console.error("[oauth-proxy]", e);
287
+ return jsonError("server_error", "Refresh-token signing is not configured", 500);
288
+ }
289
+ return Response.json({
290
+ access_token: entry.access_token,
291
+ token_type: "bearer",
292
+ expires_in: ACCESS_TTL,
293
+ refresh_token: refresh,
294
+ });
295
+ }
296
+ async function handleRefreshToken(params) {
297
+ const { refresh_token, client_id } = params;
298
+ if (!refresh_token || !client_id) {
299
+ return jsonError("invalid_request", "Missing required parameters (refresh_token, client_id)");
300
+ }
301
+ let decoded;
302
+ try {
303
+ decoded = verifyRefresh(refresh_token);
304
+ }
305
+ catch (e) {
306
+ console.error("[oauth-proxy]", e);
307
+ return jsonError("server_error", "Refresh-token verification is not configured", 500);
308
+ }
309
+ if (!decoded)
310
+ return jsonError("invalid_grant", "Invalid or expired refresh token");
311
+ if (decoded.clientId !== client_id)
312
+ return jsonError("invalid_grant", "client_id does not match");
313
+ const wosClientId = workosClientId();
314
+ if (!wosClientId)
315
+ return jsonError("server_error", "WORKOS_CLIENT_ID is not configured", 500);
316
+ try {
317
+ const auth = await getWorkOS().userManagement.authenticateWithRefreshToken({
318
+ clientId: wosClientId,
319
+ refreshToken: decoded.workosRefreshToken,
320
+ });
321
+ return Response.json({
322
+ access_token: auth.accessToken,
323
+ token_type: "bearer",
324
+ expires_in: ACCESS_TTL,
325
+ refresh_token: signRefresh(auth.refreshToken, client_id),
326
+ });
327
+ }
328
+ catch (e) {
329
+ console.error("[oauth-proxy] refresh exchange failed:", e);
330
+ return jsonError("invalid_grant", "Refresh token is no longer valid. Please re-authenticate.");
331
+ }
332
+ }
333
+ async function readBody(request) {
334
+ const ct = request.headers.get("content-type") ?? "";
335
+ try {
336
+ if (ct.includes("application/x-www-form-urlencoded")) {
337
+ const form = await request.formData();
338
+ const out = {};
339
+ form.forEach((v, k) => {
340
+ out[k] = String(v);
341
+ });
342
+ return out;
343
+ }
344
+ return (await request.json());
345
+ }
346
+ catch {
347
+ return null;
348
+ }
349
+ }
350
+ /** POST /oauth/token — authorization_code + refresh_token, plus whatever
351
+ * `claimGrant` chains in (auth.md's claim grant, in practice). */
352
+ async function token(request) {
353
+ prune();
354
+ const params = await readBody(request);
355
+ if (!params)
356
+ return jsonError("invalid_request", "Invalid request body");
357
+ if (params.grant_type === "authorization_code")
358
+ return handleAuthorizationCode(params);
359
+ if (params.grant_type === "refresh_token")
360
+ return handleRefreshToken(params);
361
+ const chained = typeof opts.claimGrant === "function" ? opts.claimGrant() : opts.claimGrant;
362
+ if (chained && params.grant_type === chained.type)
363
+ return chained.handle(params);
364
+ const supported = ["authorization_code", "refresh_token", chained?.type]
365
+ .filter(Boolean)
366
+ .join(", ");
367
+ return jsonError("unsupported_grant_type", `Supported grant types: ${supported}`);
368
+ }
369
+ return {
370
+ register,
371
+ authorize,
372
+ callback,
373
+ token,
374
+ /** Grant types to advertise in AS metadata. */
375
+ grantTypes: ["authorization_code", "refresh_token"],
376
+ /** AS-metadata fields this proxy adds — merge into the discovery document so
377
+ * the endpoints are only advertised where they actually exist. */
378
+ asMetadata: (request) => ({
379
+ authorization_endpoint: `${baseUrlOf(request)}${paths.authorize}`,
380
+ registration_endpoint: `${baseUrlOf(request)}${paths.register}`,
381
+ }),
382
+ paths,
383
+ };
384
+ }
385
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth-proxy/index.ts"],"names":[],"mappings":"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"}