@onyxsecurity/mcp-gateway 2.1.41 → 2.1.42
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.
- package/dist/bin/mcp-gateway.js +2 -2
- package/dist/{cli-iLlbNqMw.js → cli-DTkYkHaa.js} +2 -2
- package/dist/{cli-iLlbNqMw.js.map → cli-DTkYkHaa.js.map} +1 -1
- package/dist/{env-DvKbtn5P.js → env-BXOysH5D.js} +2 -2
- package/dist/{env-DvKbtn5P.js.map → env-BXOysH5D.js.map} +1 -1
- package/dist/{env-BYymL5qu.js → env-BsWYwatz.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{logger-C9UQmiLF.js → logger-VdxpdGse.js} +2 -2
- package/dist/{logger-C9UQmiLF.js.map → logger-VdxpdGse.js.map} +1 -1
- package/dist/{main-Cw-GpTlP.js → main-7pgTjUUY.js} +2 -2
- package/dist/{main-Cw-GpTlP.js.map → main-7pgTjUUY.js.map} +1 -1
- package/dist/{oauthProvidersClient-DBwig3Kv.js → oauthProvidersClient-DBgwx2Yu.js} +2 -2
- package/dist/{oauthProvidersClient-DBwig3Kv.js.map → oauthProvidersClient-DBgwx2Yu.js.map} +1 -1
- package/dist/oauthProvidersClient-zRPsOWjs.js +1 -0
- package/dist/{providers-ITwJPvLY.js → providers-Dw-nuigJ.js} +2 -2
- package/dist/{providers-ITwJPvLY.js.map → providers-Dw-nuigJ.js.map} +1 -1
- package/dist/{transportDetection-di7mtGu9.js → transportDetection-C0T6rQqt.js} +2 -2
- package/dist/{transportDetection-di7mtGu9.js.map → transportDetection-C0T6rQqt.js.map} +1 -1
- package/dist/{upstreamNegotiation-DXOdQ605.js → upstreamNegotiation-bWTIQmfK.js} +2 -2
- package/dist/{upstreamNegotiation-DXOdQ605.js.map → upstreamNegotiation-bWTIQmfK.js.map} +1 -1
- package/package.json +1 -1
- package/dist/oauthProvidersClient-BPHPTMIw.js +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{logger as e}from"./logger-
|
|
2
|
-
//# sourceMappingURL=oauthProvidersClient-
|
|
1
|
+
import{logger as e}from"./logger-VdxpdGse.js";import{setOAuthProviders as t}from"./providers-Dw-nuigJ.js";async function n(e){let t=new URL(e.url),n=t.hostname===`localhost`||t.hostname===`127.0.0.1`||t.hostname===`::1`||t.hostname===`[::1]`;if(t.protocol!==`https:`&&!n)throw Error(`OAuth providers URL must use HTTPS, got ${t.protocol}`);let r=new AbortController,i=setTimeout(()=>r.abort(),e.timeoutMs);try{let t=await fetch(e.url,{headers:{Accept:`application/json`,apikey:e.apiKey},method:`GET`,signal:r.signal});if(!t.ok)throw Error(`OAuth providers service returned ${t.status}: ${t.statusText}`);let n=await t.json();return Array.isArray(n.providers)?n.providers:[]}catch(t){throw t instanceof Error&&t.name===`AbortError`?Error(`OAuth providers fetch timed out after ${e.timeoutMs}ms`):t}finally{clearTimeout(i)}}async function r(r){if(!r.enabled||!r.url||!r.apiKey){t([]),e.debug(`OAuth providers fetch disabled (missing URL or API key); skipping`);return}try{let i=await n({apiKey:r.apiKey,timeoutMs:r.timeoutMs,url:r.url});t(i),e.info(`OAuth providers loaded`,{count:i.length,ids:i.map(e=>e.id)})}catch(n){t([]),e.warn(`OAuth providers fetch failed; falling back to DCR`,{error:String(n),url:r.url})}}export{n as fetchOAuthProviders,r as initializeOAuthProviders};
|
|
2
|
+
//# sourceMappingURL=oauthProvidersClient-DBgwx2Yu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthProvidersClient-
|
|
1
|
+
{"version":3,"file":"oauthProvidersClient-DBgwx2Yu.js","names":[],"sources":["../src/auth/oauthProvidersClient.ts"],"sourcesContent":["import type { OAuthProviderConfig } from \"../config/config.js\";\n\nimport { logger } from \"../lib/logger.js\";\nimport { setOAuthProviders } from \"./providers.js\";\n\nexport interface InitializeOAuthProvidersConfig {\n apiKey: string | undefined;\n enabled: boolean;\n timeoutMs: number;\n url: null | string;\n}\n\nexport interface OAuthProvidersClientConfig {\n apiKey: string;\n timeoutMs: number;\n url: string;\n}\n\ninterface OAuthProvidersResponse {\n providers?: OAuthProviderConfig[];\n}\n\n/**\n * Fetches the OAuth provider list from the web extension service.\n *\n * The endpoint is gated by Kong's key-auth plugin, which validates the\n * `apikey` header and forwards a per-tenant `x-consumer-username` header\n * (e.g. `mcp-gateway@<tenantUUID>`) to the backend.\n *\n * Throws on network error, timeout, or non-2xx response. Callers are\n * expected to handle errors and decide on a fallback (initializeOAuthProviders\n * fails open by emptying the in-memory provider list, which causes the OAuth\n * flow to fall through to Dynamic Client Registration).\n */\nexport async function fetchOAuthProviders(\n cfg: OAuthProvidersClientConfig\n): Promise<OAuthProviderConfig[]> {\n // Reject non-HTTPS URLs before sending the API key over the wire.\n // Loopback addresses are allowed for local development against a non-TLS\n // stub: \"localhost\", IPv4 (127.0.0.1), and IPv6 (::1). Node returns the\n // bracketed form (\"[::1]\") for IPv6 hosts in URL.hostname, so match both.\n const parsed = new URL(cfg.url);\n const isLocal =\n parsed.hostname === \"localhost\" ||\n parsed.hostname === \"127.0.0.1\" ||\n parsed.hostname === \"::1\" ||\n parsed.hostname === \"[::1]\";\n if (parsed.protocol !== \"https:\" && !isLocal) {\n throw new Error(`OAuth providers URL must use HTTPS, got ${parsed.protocol}`);\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), cfg.timeoutMs);\n\n try {\n const response = await fetch(cfg.url, {\n // GET with no body — Accept signals the desired response format,\n // Content-Type would be misleading.\n headers: {\n Accept: \"application/json\",\n apikey: cfg.apiKey,\n },\n method: \"GET\",\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`OAuth providers service returned ${response.status}: ${response.statusText}`);\n }\n\n const body = (await response.json()) as OAuthProvidersResponse;\n return Array.isArray(body.providers) ? body.providers : [];\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(`OAuth providers fetch timed out after ${cfg.timeoutMs}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Initializes the in-memory OAuth provider store at gateway startup.\n *\n * On a successful fetch, populates the store with the providers returned by\n * the web extension service. On any failure (disabled config, network error,\n * timeout, malformed body), empties the store and logs a warning. The OAuth\n * flow at oauthFlow.ts then falls through to Dynamic Client Registration,\n * matching the gateway's \"fail-safe by default\" convention.\n */\nexport async function initializeOAuthProviders(cfg: InitializeOAuthProvidersConfig): Promise<void> {\n if (!cfg.enabled || !cfg.url || !cfg.apiKey) {\n setOAuthProviders([]);\n logger.debug(\"OAuth providers fetch disabled (missing URL or API key); skipping\");\n return;\n }\n\n try {\n const providers = await fetchOAuthProviders({\n apiKey: cfg.apiKey,\n timeoutMs: cfg.timeoutMs,\n url: cfg.url,\n });\n setOAuthProviders(providers);\n logger.info(\"OAuth providers loaded\", {\n count: providers.length,\n ids: providers.map((p) => p.id),\n });\n } catch (error) {\n setOAuthProviders([]);\n logger.warn(\"OAuth providers fetch failed; falling back to DCR\", {\n error: String(error),\n url: cfg.url,\n });\n }\n}\n"],"mappings":"0GAkCA,eAAsB,EACpB,EACgC,CAKhC,IAAM,EAAS,IAAI,IAAI,EAAI,IAAI,CACzB,EACJ,EAAO,WAAa,aACpB,EAAO,WAAa,aACpB,EAAO,WAAa,OACpB,EAAO,WAAa,QACtB,GAAI,EAAO,WAAa,UAAY,CAAC,EACnC,MAAU,MAAM,2CAA2C,EAAO,WAAW,CAG/E,IAAM,EAAa,IAAI,gBACjB,EAAQ,eAAiB,EAAW,OAAO,CAAE,EAAI,UAAU,CAEjE,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,EAAI,IAAK,CAGpC,QAAS,CACP,OAAQ,mBACR,OAAQ,EAAI,OACb,CACD,OAAQ,MACR,OAAQ,EAAW,OACpB,CAAC,CAEF,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,oCAAoC,EAAS,OAAO,IAAI,EAAS,aAAa,CAGhG,IAAM,EAAQ,MAAM,EAAS,MAAM,CACnC,OAAO,MAAM,QAAQ,EAAK,UAAU,CAAG,EAAK,UAAY,EAAE,OACnD,EAAO,CAId,MAHI,aAAiB,OAAS,EAAM,OAAS,aACjC,MAAM,yCAAyC,EAAI,UAAU,IAAI,CAEvE,SACE,CACR,aAAa,EAAM,EAavB,eAAsB,EAAyB,EAAoD,CACjG,GAAI,CAAC,EAAI,SAAW,CAAC,EAAI,KAAO,CAAC,EAAI,OAAQ,CAC3C,EAAkB,EAAE,CAAC,CACrB,EAAO,MAAM,oEAAoE,CACjF,OAGF,GAAI,CACF,IAAM,EAAY,MAAM,EAAoB,CAC1C,OAAQ,EAAI,OACZ,UAAW,EAAI,UACf,IAAK,EAAI,IACV,CAAC,CACF,EAAkB,EAAU,CAC5B,EAAO,KAAK,yBAA0B,CACpC,MAAO,EAAU,OACjB,IAAK,EAAU,IAAK,GAAM,EAAE,GAAG,CAChC,CAAC,OACK,EAAO,CACd,EAAkB,EAAE,CAAC,CACrB,EAAO,KAAK,oDAAqD,CAC/D,MAAO,OAAO,EAAM,CACpB,IAAK,EAAI,IACV,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./env-BXOysH5D.js";import"./logger-VdxpdGse.js";import"./providers-Dw-nuigJ.js";import{fetchOAuthProviders as e,initializeOAuthProviders as t}from"./oauthProvidersClient-DBgwx2Yu.js";export{t as initializeOAuthProviders};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{logger as e}from"./logger-
|
|
2
|
-
//# sourceMappingURL=providers-
|
|
1
|
+
import{logger as e}from"./logger-VdxpdGse.js";let t=[];function n(n){let r=typeof n==`string`?new URL(n):n,o=r.hostname.toLowerCase();for(let n of t)for(let t of n.urlPatterns){let r=t.toLowerCase();if(a(o,r))return e.debug(`Found matching OAuth provider for URL`,{hostname:o,pattern:t,providerId:n.id,providerName:n.name}),i(n)}e.debug(`No pre-configured OAuth provider found for URL`,{hostname:o,serverUrl:r.toString()})}function r(e){t=e.map(i)}function i(e){return{...e,scopes:e.scopes?[...e.scopes]:void 0,urlPatterns:[...e.urlPatterns]}}function a(e,t){return!!(e===t||e.endsWith(`.${t}`))}export{n as findProviderForUrl,r as setOAuthProviders};
|
|
2
|
+
//# sourceMappingURL=providers-Dw-nuigJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers-
|
|
1
|
+
{"version":3,"file":"providers-Dw-nuigJ.js","names":["oauthProviders: OAuthProviderConfig[]"],"sources":["../src/auth/providers.ts"],"sourcesContent":["import type { OAuthProviderConfig } from \"../config/config.js\";\n\nimport { logger } from \"../lib/logger.js\";\n\n// Mutable store. Populated by setOAuthProviders() during startup once the\n// gateway has fetched provider config from the web extension service.\n// Pre-startup or when the fetch fails, the array stays empty and OAuth flows\n// fall through to Dynamic Client Registration via oauthFlow.ts.\nlet oauthProviders: OAuthProviderConfig[] = [];\n\n/**\n * Finds a pre-configured OAuth provider that matches the given server URL.\n *\n * @param serverUrl The MCP server URL to match against provider URL patterns\n * @returns The matching provider config, or undefined if no match found\n */\nexport function findProviderForUrl(serverUrl: string | URL): OAuthProviderConfig | undefined {\n const serverUrlObj = typeof serverUrl === \"string\" ? new URL(serverUrl) : serverUrl;\n const hostname = serverUrlObj.hostname.toLowerCase();\n\n for (const provider of oauthProviders) {\n for (const pattern of provider.urlPatterns) {\n // Pattern can be a hostname or a hostname with path prefix\n const patternLower = pattern.toLowerCase();\n\n // Check if pattern matches hostname (with or without subdomains)\n if (matchesHostname(hostname, patternLower)) {\n logger.debug(\"Found matching OAuth provider for URL\", {\n hostname,\n pattern,\n providerId: provider.id,\n providerName: provider.name,\n });\n // Return a defensive clone — callers in oauthFlow.ts must not be\n // able to corrupt the in-memory store via the returned reference.\n return cloneProvider(provider);\n }\n }\n }\n\n logger.debug(\"No pre-configured OAuth provider found for URL\", {\n hostname,\n serverUrl: serverUrlObj.toString(),\n });\n return undefined;\n}\n\n/**\n * Gets a provider by its ID.\n *\n * @param providerId The provider ID (e.g., \"github\")\n * @returns The provider config, or undefined if not found\n */\nexport function getProviderById(providerId: string): OAuthProviderConfig | undefined {\n const found = oauthProviders.find((p) => p.id === providerId);\n return found ? cloneProvider(found) : undefined;\n}\n\n/**\n * Lists all configured OAuth providers.\n * Useful for debugging and admin interfaces.\n *\n * @returns Array of provider summaries (without secrets)\n */\nexport function listProviders(): Array<{\n hasClientSecret: boolean;\n id: string;\n name: string;\n urlPatterns: string[];\n}> {\n return oauthProviders.map((p) => ({\n hasClientSecret: !!p.clientSecret,\n id: p.id,\n name: p.name,\n urlPatterns: [...p.urlPatterns],\n }));\n}\n\n/**\n * Replaces the in-memory OAuth provider list. Called once at gateway startup\n * after fetching from the web extension service. Pass an empty array to clear.\n *\n * Stores defensive shallow copies of each provider so that callers cannot\n * mutate the in-memory store via the references they passed in. The\n * urlPatterns array is also cloned for the same reason.\n */\nexport function setOAuthProviders(providers: OAuthProviderConfig[]): void {\n oauthProviders = providers.map(cloneProvider);\n}\n\n// cloneProvider returns a defensive shallow copy with array fields cloned,\n// so callers can read and even mutate the result without corrupting the\n// in-memory store. Used on every read path (findProviderForUrl,\n// getProviderById) to match the write-side contract in setOAuthProviders.\nfunction cloneProvider(p: OAuthProviderConfig): OAuthProviderConfig {\n return {\n ...p,\n scopes: p.scopes ? [...p.scopes] : undefined,\n urlPatterns: [...p.urlPatterns],\n };\n}\n\n/**\n * Checks if a hostname matches a pattern.\n * Supports exact matches and subdomain matches.\n *\n * @param hostname The hostname to check (e.g., \"api.github.com\")\n * @param pattern The pattern to match against (e.g., \"github.com\")\n * @returns true if the hostname matches the pattern\n */\nfunction matchesHostname(hostname: string, pattern: string): boolean {\n // Exact match\n if (hostname === pattern) {\n return true;\n }\n\n // Subdomain match: hostname ends with \".pattern\"\n // e.g., \"api.github.com\" matches \"github.com\"\n if (hostname.endsWith(`.${pattern}`)) {\n return true;\n }\n\n return false;\n}\n"],"mappings":"8CAQA,IAAIA,EAAwC,EAAE,CAQ9C,SAAgB,EAAmB,EAA0D,CAC3F,IAAM,EAAe,OAAO,GAAc,SAAW,IAAI,IAAI,EAAU,CAAG,EACpE,EAAW,EAAa,SAAS,aAAa,CAEpD,IAAK,IAAM,KAAY,EACrB,IAAK,IAAM,KAAW,EAAS,YAAa,CAE1C,IAAM,EAAe,EAAQ,aAAa,CAG1C,GAAI,EAAgB,EAAU,EAAa,CASzC,OARA,EAAO,MAAM,wCAAyC,CACpD,WACA,UACA,WAAY,EAAS,GACrB,aAAc,EAAS,KACxB,CAAC,CAGK,EAAc,EAAS,CAKpC,EAAO,MAAM,iDAAkD,CAC7D,WACA,UAAW,EAAa,UAAU,CACnC,CAAC,CA2CJ,SAAgB,EAAkB,EAAwC,CACxE,EAAiB,EAAU,IAAI,EAAc,CAO/C,SAAS,EAAc,EAA6C,CAClE,MAAO,CACL,GAAG,EACH,OAAQ,EAAE,OAAS,CAAC,GAAG,EAAE,OAAO,CAAG,IAAA,GACnC,YAAa,CAAC,GAAG,EAAE,YAAY,CAChC,CAWH,SAAS,EAAgB,EAAkB,EAA0B,CAYnE,MAJA,GANI,IAAa,GAMb,EAAS,SAAS,IAAI,IAAU"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{config as e}from"./env-
|
|
1
|
+
import{config as e}from"./env-BXOysH5D.js";import{logger as t}from"./logger-VdxpdGse.js";import{OAuthError as n,OAuthErrorCode as r,SSEClientTransport as i,StreamableHTTPClientTransport as a,discoverAuthorizationServerMetadata as o,discoverOAuthProtectedResourceMetadata as s,exchangeAuthorization as c,normalizeUrl as l,refreshAuthorization as u,registerClient as d,startAuthorization as f}from"./normalizeUrl-DoppHGlo.js";import{findProviderForUrl as p}from"./providers-Dw-nuigJ.js";import{platform as m}from"node:os";import{URL as h}from"node:url";import{createServer as g}from"node:http";import{execFile as _}from"node:child_process";async function v(e){let n=e.toString(),r=m(),i=S(n);return new Promise((e,a)=>{let o,s;if(r===`win32`){let e=`Start-Process ${b(n)}`,t=y(e);o=x(),s=[`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Bypass`,`-EncodedCommand`,t]}else r===`darwin`?(o=`open`,s=[n]):(o=`xdg-open`,s=[n]);_(o,s,(n,s,c)=>{if(n){let e={command:o,os:r,stderr:c,url:i};t.warn(`Failed to open browser automatically`,{...e,error:n.message});let s=Error(`Failed to open browser: ${n.message} (command: ${o}, os: ${r}, url: ${i})`);s.cause=n,a(s)}else t.debug(`Browser opened successfully`,{url:i}),e()})})}function y(e){return Buffer.from(e,`utf16le`).toString(`base64`)}function b(e){return`'${e.replaceAll(`'`,`''`)}'`}function x(){return`${process.env.SYSTEMROOT||process.env.windir||`C:\\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`}function S(e){try{let t=new URL(e);return t.search?`${t.protocol}//${t.host}${t.pathname}?[REDACTED]`:`${t.protocol}//${t.host}${t.pathname}`}catch{return`[INVALID_URL]`}}const C={CALLBACK_FAILED:`mcp_auth_callback_failed`,DCR_FAILED:`mcp_auth_dcr_failed`,REFRESH_FAILED:`mcp_auth_refresh_failed`,SERVER_METADATA_FAILED:`mcp_auth_server_metadata_failed`,STATE_MISMATCH:`mcp_auth_state_mismatch`,TOKEN_EXCHANGE_FAILED:`mcp_auth_token_exchange_failed`},w=49152;function T(){return Math.floor(Math.random()*(65535-w+1))+w}function E(e,t){return new Promise((n,r)=>{let i=t=>{e.removeListener(`listening`,a),r(t)},a=()=>{e.removeListener(`error`,i),n()};e.once(`error`,i),e.once(`listening`,a),e.listen(t,`127.0.0.1`)})}async function D(e={}){let{maxAttempts:n=5,preferredPort:r,serverUrl:i,timeoutMs:a=3e5}=e,o=i?A(i):void 0,s,c,l={},u=new Promise((e,t)=>{s=e,c=t}),d,f=g((e,n)=>{if(e.url===`/favicon.ico`){n.writeHead(404),n.end();return}if(!e.url?.startsWith(`/callback`)){n.writeHead(404),n.end(`Not Found`);return}try{let r=new h(e.url,`http://localhost:${d}`),i=r.searchParams.get(`code`),a=r.searchParams.get(`error`),u=r.searchParams.get(`error_description`),p=r.searchParams.get(`state`);if(a){t.error(`OAuth authorization error`,{error:a,errorDescription:u,eventType:C.CALLBACK_FAILED,...o?{serverUrl:o}:{}}),n.writeHead(400,{"Content-Type":`text/html`}),n.end(k(a,u||void 0)),clearTimeout(l.id),c(Error(`OAuth authorization failed: ${a}${u?` - ${u}`:``}`));return}if(!i){t.error(`OAuth callback missing authorization code`,{eventType:C.CALLBACK_FAILED,reason:`missing_code`,...o?{serverUrl:o}:{}}),n.writeHead(400,{"Content-Type":`text/html`}),n.end(k(`missing_code`,`No authorization code was provided`)),clearTimeout(l.id),c(Error(`OAuth callback missing authorization code`));return}t.info(`OAuth authorization code received`,{codePrefix:`${i.substring(0,10)}...`,hasState:!!p}),n.writeHead(200,{"Content-Type":`text/html`}),n.end(`<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
@@ -133,4 +133,4 @@ import{config as e}from"./env-DvKbtn5P.js";import{logger as t}from"./logger-C9UQ
|
|
|
133
133
|
</div>
|
|
134
134
|
</body>
|
|
135
135
|
</html>`}function A(e){try{let t=new h(e);return t.username=``,t.password=``,t.search=``,t.hash=``,t.toString()}catch{return e}}var j=class extends Error{constructor(e,t){let n=t instanceof Error?t.message:String(t);super(`Auth server metadata discovery failed for ${e}: ${n}`),this.authServerUrl=e,this.cause=t,this.name=`AuthServerDiscoveryError`}};async function M(e,t={}){let{logger:n,signal:r}=t,i=r?N(r):void 0;n?.debug(`Discovering OAuth protected resource metadata...`);let a;try{a=i?await s(e,void 0,i):await s(e),n?.info(`Discovered protected resource metadata`,{authorizationServers:a?.authorization_servers,resource:a?.resource,scopesSupported:a?.scopes_supported})}catch(e){n?.warn(`Could not discover protected resource metadata, will try direct discovery`,{error:String(e)})}let c;a?.authorization_servers?.length?(c=new URL(a.authorization_servers[0]),n?.debug(`Using authorization server from resource metadata`,{authServerUrl:c.toString()})):(c=e,n?.debug(`Using server URL as authorization server`,{authServerUrl:c.toString()})),n?.debug(`Discovering authorization server metadata...`);let l;try{l=await o(c,{fetchFn:i,skipIssuerValidation:!0})}catch(e){throw new j(c,e)}if(!l&&c.pathname!==`/`){let e=new URL(c.origin);n?.debug(`Auth server metadata absent at path-aware well-knowns, retrying at origin root`,{authServerUrl:c.toString(),rootUrl:e.toString()});try{l=await o(e,{fetchFn:i,skipIssuerValidation:!0})}catch(t){if(r?.aborted)throw new j(e,t);n?.warn(`Origin-root auth server metadata fallback failed, treating metadata as absent`,{error:String(t),rootUrl:e.toString()})}l?(c=e,n?.info(`Origin-root auth server metadata fallback succeeded`,{authServerUrl:c.toString()})):n?.debug(`Origin-root auth server metadata fallback found nothing`,{rootUrl:e.toString()})}return l&&n?.info(`Discovered authorization server metadata`,{authorizationEndpoint:l.authorization_endpoint,issuer:l.issuer,registrationEndpoint:l.registration_endpoint,tokenEndpoint:l.token_endpoint}),{authMetadata:l,authServerUrl:c,resourceMetadata:a}}function N(e){return(t,n)=>{let r=n?.signal,i=r?AbortSignal.any([e,r]):e;return fetch(t,{...n,signal:i})}}function P(e){return F(e,r.InvalidClient,new WeakSet)}function ee(e){return F(e,r.InvalidGrant,new WeakSet)}function F(e,t,r){if(e==null)return!1;if(e instanceof n)return e.code===t;if(typeof e==`object`){if(r.has(e))return!1;r.add(e);let n=e.error;if(typeof n==`string`&&n===t)return!0;for(let n of[`response`,`data`,`body`,`cause`]){let i=e[n];if(i!==void 0&&F(i,t,r))return!0}}return e instanceof Error&&typeof e.message==`string`?RegExp(`"error"\\s*:\\s*"${t}"`).test(e.message)||RegExp(`\\berror\\s*=\\s*${t}\\b`).test(e.message)||RegExp(`\\berror\\s*:\\s*${t}\\b`).test(e.message):!1}const I={"claude-code":`Claude Code (mcp-gateway)`,codex:`Codex`,copilot:`Visual Studio Code`,cursor:`Cursor`,opencode:`OpenCode`},L={copilot:`https://code.visualstudio.com`},R={cursor:{"mcp.figma.com":`cursor://anysphere.cursor-mcp/oauth/callback`}};function z(){return U(e.clientAppName)}function B(){return W(e.clientAppName)}function V(t,n){return G(e.clientAppName,t,n)}async function H(e,n={}){let{credentialStore:r,scope:i,timeoutMs:a}=n,o=l(e),s=new URL(o);if(t.info(`Starting OAuth flow`,{serverUrl:o}),r){let e=await Y(s,r);if(e)return t.info(`Using existing OAuth credentials`,{clientId:e.clientInfo.client_id,serverUrl:o}),e}t.debug(`Starting OAuth callback server...`);let u=await D({serverUrl:o,timeoutMs:a}),m=u.callbackUrl;t.info(`OAuth callback server started`,{callbackUrl:m,port:u.port});try{let e=p(s);if(e)return t.info(`Using pre-configured OAuth provider`,{providerId:e.id,providerName:e.name}),await J(s,e,u,r,i);let a,l,h;try{({authMetadata:a,authServerUrl:l,resourceMetadata:h}=await M(s,{logger:t}))}catch(e){throw t.error(`Auth server metadata discovery failed`,{error:String(e),eventType:C.SERVER_METADATA_FAILED,serverUrl:o,...e instanceof j?{authServer:e.authServerUrl.toString()}:{}}),e}if(!a)throw t.error(`Auth server metadata absent (server may not support OAuth 2.0)`,{authServer:l.toString(),eventType:C.SERVER_METADATA_FAILED,reason:`metadata_absent`,serverUrl:o}),Error(`Could not discover OAuth metadata from ${l}. The server may not support OAuth 2.0 or the metadata endpoint is not accessible.`);let g=h?.scopes_supported,_=g?.includes(`offline_access`)??!1,y=i??(_?g?.join(` `):void 0);y&&!i?t.info(`Defaulting OAuth scope to the resource's advertised scopes_supported`,{scope:y,serverUrl:o}):!i&&g?.length&&t.debug(`Resource advertises scopes but not offline_access; requesting no scope`,{advertised:g,serverUrl:o});let b,x=r?await r.load(o):void 0,S=x?.clientInfo?.redirect_uris||[];if(x?.clientInfo&&S.includes(m)&&x?.clientInfo)t.info(`Reusing existing DCR client registration`,{clientId:x.clientInfo.client_id,clientName:x.clientInfo.client_name,redirectUri:m}),b=x.clientInfo;else{x?.clientInfo&&t.info(`Existing DCR client has different redirect_uri, re-registering`,{existingRedirectUris:S,newRedirectUri:m});let e=n.clientMetadata?.client_uri??B(),i={client_name:n.clientMetadata?.client_name||z(),...e&&{client_uri:e},grant_types:n.clientMetadata?.grant_types||[`authorization_code`,`refresh_token`],redirect_uris:V(s,m),response_types:n.clientMetadata?.response_types||[`code`],token_endpoint_auth_method:n.clientMetadata?.token_endpoint_auth_method||`none`,...y&&{scope:y}};if(t.debug(`Client metadata for DCR`,{clientMetadata:i}),!a.registration_endpoint)throw t.error(`DCR registration unsupported by auth server`,{authServer:l.toString(),eventType:C.DCR_FAILED,reason:`no_registration_endpoint`,serverUrl:o}),Error(`Authorization server does not support Dynamic Client Registration. No registration_endpoint found in metadata.`);t.info(`Registering client via DCR...`,{registrationEndpoint:a.registration_endpoint});try{b=await d(l,{clientMetadata:i,metadata:a})}catch(e){throw t.error(`DCR registration failed`,{authServer:l.toString(),error:String(e),eventType:C.DCR_FAILED,registrationEndpoint:a.registration_endpoint,serverUrl:o}),e}t.info(`Client registered successfully via DCR`,{clientId:b.client_id,clientName:b.client_name,clientSecretExpiresAt:b.client_secret_expires_at}),r&&await r.update(o,{clientInfo:b})}let w=crypto.randomUUID();t.debug(`Starting authorization flow...`);let{authorizationUrl:T,codeVerifier:E}=await f(l,{clientInformation:b,metadata:a,redirectUrl:m,scope:y,state:w});await v(T),t.debug(`Waiting for OAuth callback...`);let D=await u.waitForCallback();if(D.state!==w)throw t.error(`OAuth state mismatch — possible CSRF attack`,{authServer:l.toString(),eventType:C.STATE_MISMATCH,serverUrl:o}),Error(`OAuth state mismatch - possible CSRF attack`);t.info(`Authorization code received`,{codePrefix:`${D.code.substring(0,10)}...`}),t.debug(`Exchanging authorization code for tokens...`);let O;try{O=await c(l,{authorizationCode:D.code,clientInformation:b,codeVerifier:E,metadata:a,redirectUri:m})}catch(e){throw t.error(`Token exchange failed`,{authServer:l.toString(),clientId:b.client_id,error:String(e),eventType:C.TOKEN_EXCHANGE_FAILED,grantType:`authorization_code`,serverUrl:o}),e}if(t.info(`OAuth tokens obtained successfully`,{expiresIn:O.expires_in,grantedScope:O.scope,hasRefreshToken:!!O.refresh_token,requestedScope:y,tokenType:O.token_type}),r){let e=new Date().toISOString();await r.update(o,{tokens:O,tokensObtainedAt:e}),t.info(`OAuth credentials persisted to disk`,{serverUrl:o})}return{clientInfo:b,fromCache:!1,tokens:O}}finally{await u.close()}}function U(e){let t=e?.trim().toLowerCase();return t&&Object.hasOwn(I,t)?I[t]:`MCP Gateway`}function W(e){let t=e?.trim().toLowerCase();if(t)return Object.hasOwn(L,t)?L[t]:void 0}function G(e,t,n){let r=e?.trim().toLowerCase();if(!r)return[n];let i=R[r];if(!i)return[n];let a;try{a=(t instanceof URL?t:new URL(t)).hostname.toLowerCase()}catch{return[n]}let o=i[a];return o?[o,n]:[n]}async function K(e,t){let n=typeof e==`string`?new URL(e):e,r=await t.load(n.toString());if(!(!r?.clientInfo||!r.tokens?.refresh_token))return X(n,r,t)}async function q(e,n,r,i){let a=e.tokenEndpoint,o=e.tokenEndpointAuthMethod||(e.clientSecret?`client_secret_post`:`none`),s=new URLSearchParams;s.set(`grant_type`,`authorization_code`),s.set(`code`,n),s.set(`redirect_uri`,r),i&&s.set(`code_verifier`,i);let c={Accept:`application/json`,"Content-Type":`application/x-www-form-urlencoded`};o===`client_secret_basic`&&e.clientSecret?c.Authorization=`Basic ${Buffer.from(`${e.clientId}:${e.clientSecret}`).toString(`base64`)}`:o===`client_secret_post`&&e.clientSecret?(s.set(`client_id`,e.clientId),s.set(`client_secret`,e.clientSecret)):s.set(`client_id`,e.clientId),t.debug(`Sending token request`,{authMethod:o,providerId:e.id,tokenEndpoint:a});let l=await fetch(a,{body:s.toString(),headers:c,method:`POST`});if(!l.ok){let n=await l.text();throw t.error(`Token exchange failed`,{authMethod:o,error:n,eventType:C.TOKEN_EXCHANGE_FAILED,grantType:`authorization_code`,httpStatus:l.status,providerId:e.id,tokenEndpoint:a}),Error(`Token exchange failed: ${l.status} ${n}`)}let u=l.headers.get(`content-type`)||``,d;if(u.includes(`application/json`))d=await l.json();else if(u.includes(`application/x-www-form-urlencoded`)||u.includes(`text/plain`)){let e=await l.text(),t=new URLSearchParams(e);d=Object.fromEntries(t.entries())}else{let e=await l.text();try{d=JSON.parse(e)}catch{let t=new URLSearchParams(e);d=Object.fromEntries(t.entries())}}return typeof d.expires_in==`string`&&(d.expires_in=parseInt(d.expires_in,10)),{access_token:d.access_token,expires_in:d.expires_in,refresh_token:d.refresh_token,scope:d.scope,token_type:d.token_type||`bearer`}}async function J(e,n,r,i,a){let o=e.toString(),s=r.callbackUrl,c={client_id:n.clientId,client_name:n.name,client_secret:n.clientSecret,redirect_uris:[s],token_endpoint_auth_method:n.tokenEndpointAuthMethod||(n.clientSecret?`client_secret_post`:`none`)};t.info(`Using pre-configured OAuth client`,{clientId:n.clientId,hasClientSecret:!!n.clientSecret,providerId:n.id,tokenEndpointAuthMethod:c.token_endpoint_auth_method});let l=a||n.scopes?.join(` `),u=n.usePkce!==!1,d,f,p;if(u){let{generateCodeChallenge:e,generateCodeVerifier:t}=await import(`./pkce-CYE2WffE.js`);d=t(),f=await e(d),p=`S256`}let m=new URL(n.authorizationEndpoint);m.searchParams.set(`client_id`,n.clientId),m.searchParams.set(`redirect_uri`,s),m.searchParams.set(`response_type`,`code`),l&&m.searchParams.set(`scope`,l);let h=crypto.randomUUID();m.searchParams.set(`state`,h),f&&p&&(m.searchParams.set(`code_challenge`,f),m.searchParams.set(`code_challenge_method`,p)),await v(m),t.debug(`Waiting for OAuth callback...`);let g=await r.waitForCallback();if(g.state!==h)throw t.error(`OAuth state mismatch — possible CSRF attack`,{eventType:C.STATE_MISMATCH,providerId:n.id,serverUrl:o}),Error(`OAuth state mismatch - possible CSRF attack`);t.info(`Authorization code received`,{codePrefix:`${g.code.substring(0,10)}...`,providerId:n.id}),t.debug(`Exchanging authorization code for tokens...`);let _=await q(n,g.code,s,d);if(t.info(`OAuth tokens obtained successfully`,{expiresIn:_.expires_in,hasRefreshToken:!!_.refresh_token,providerId:n.id,tokenType:_.token_type}),i){let e=new Date().toISOString();await i.update(o,{clientInfo:c,tokens:_,tokensObtainedAt:e}),t.info(`OAuth credentials persisted to disk`,{providerId:n.id,serverUrl:o})}return{clientInfo:c,fromCache:!1,tokens:_}}async function Y(e,n){let r=await n.load(e.toString());if(!r){t.debug(`No stored credentials found`,{serverUrl:e.toString()});return}if(!r.clientInfo){t.debug(`Stored credentials have no client info`,{serverUrl:e.toString()});return}if(n.hasValidAccessToken(r)&&r.tokens)return t.info(`Using cached OAuth credentials with valid access token`,{clientId:r.clientInfo.client_id,serverUrl:e.toString()}),{clientInfo:r.clientInfo,fromCache:!0,tokens:r.tokens};if(n.hasRefreshToken(r)){let t=await X(e,r,n);if(t)return t}t.debug(`Stored credentials are expired and no valid refresh token`,{serverUrl:e.toString()})}async function X(e,n,r){if(!(!n.clientInfo||!n.tokens?.refresh_token)){t.info(`Attempting to refresh expired access token`,{clientId:n.clientInfo.client_id,serverUrl:e.toString()});try{let i=new AbortController,a=setTimeout(()=>i.abort(),15e3),o,s;try{({authMetadata:o,authServerUrl:s}=await M(e,{logger:t,signal:i.signal}))}finally{clearTimeout(a)}let c=await u(s,{clientInformation:n.clientInfo,metadata:o,refreshToken:n.tokens.refresh_token});t.info(`Successfully refreshed access token`,{clientId:n.clientInfo.client_id,expiresIn:c.expires_in,grantedScope:c.scope,hasNewRefreshToken:!!c.refresh_token});let l=c.refresh_token?c:{...c,refresh_token:n.tokens.refresh_token},d=new Date().toISOString();return await r.update(e.toString(),{tokens:l,tokensObtainedAt:d}),{clientInfo:n.clientInfo,fromCache:!0,tokens:l}}catch(i){let a=ee(i),o=P(i),s=a&&o,c=a&&!s,l=o&&!s;t.warn(s?`Refresh failed with both invalid_client and invalid_grant; ambiguous, retaining credentials`:l?`Client registration rejected by OAuth server (invalid_client); clearing stored client and tokens`:c?`Refresh token rejected by OAuth server (invalid_grant); clearing stored tokens`:`Token refresh failed transiently; retaining refresh_token for the next attempt`,{ambiguous:s,clientId:n.clientInfo.client_id,error:String(i),eventType:C.REFRESH_FAILED,invalidClient:l,invalidGrant:c,serverUrl:e.toString()}),l?await r.update(e.toString(),{clientInfo:void 0,tokens:void 0,tokensObtainedAt:void 0}):c&&await r.update(e.toString(),{tokens:void 0,tokensObtainedAt:void 0});return}}}const Z=[`streamable-http`,`sse`];async function Q(e,t,n,r){let{result:i,transportType:a}=await $(async i=>{let a=e(),o=te(t,i,n,r);return await a.connect(o),a});return{client:i,transportType:a}}function te(e,t,n,r){let o=new URL(e);return t===`streamable-http`?new a(o,{fetch:r,requestInit:n}):new i(o,{fetch:r,requestInit:n})}function ne(e){if(!e||typeof e!=`object`)return!1;let t=e.status,n=e.code,r=e.message;return!!(t===404||t===405||n===404||n===405||r&&/404|not found|405|method not allowed/i.test(String(r)))}async function $(e){let n=[];for(let r of Z)try{return{result:await e(r),transportType:r}}catch(e){if(ne(e)){t.info(`${r} not supported, trying next transport...`),n.push({err:e,transport:r});continue}throw e}let r=n.map(({err:e,transport:t})=>{let n=e?.status;if(n!==void 0)return`${t}: ${n}`;let r=e instanceof Error?e.message:String(e);return`${t}: ${r}`}).join(`, `),i=n.length>0?Error(`all transports returned not-supported (${r})`):Error(`No compatible transport found`);throw i.cause=n,i}export{j as AuthServerDiscoveryError,Q as connectWithTransportFallback,M as discoverAuthServer,z as getDcrClientName,B as getDcrClientUri,V as getDcrRedirectUris,H as performOAuthFlow,K as tryRefreshCachedToken,$ as walkTransports};
|
|
136
|
-
//# sourceMappingURL=transportDetection-
|
|
136
|
+
//# sourceMappingURL=transportDetection-C0T6rQqt.js.map
|