skybridge 0.0.0-dev.c14a1d3 → 0.0.0-dev.c18dbd8
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/README.md +3 -1
- package/dist/cli/build-helpers.d.ts +5 -1
- package/dist/cli/build-helpers.js +30 -10
- package/dist/cli/build-helpers.js.map +1 -1
- package/dist/cli/build-helpers.test.js +58 -3
- package/dist/cli/build-helpers.test.js.map +1 -1
- package/dist/cli/build-steps.d.ts +2 -0
- package/dist/cli/build-steps.js +73 -0
- package/dist/cli/build-steps.js.map +1 -0
- package/dist/cli/build-steps.test.js +52 -0
- package/dist/cli/build-steps.test.js.map +1 -0
- package/dist/cli/header.d.ts +1 -1
- package/dist/cli/run-plain.d.ts +18 -0
- package/dist/cli/run-plain.js +89 -0
- package/dist/cli/run-plain.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +14 -0
- package/dist/cli/use-nodemon.js +71 -60
- package/dist/cli/use-nodemon.js.map +1 -1
- package/dist/cli/use-typescript-check.d.ts +8 -2
- package/dist/cli/use-typescript-check.js +70 -67
- package/dist/cli/use-typescript-check.js.map +1 -1
- package/dist/commands/build.d.ts +0 -2
- package/dist/commands/build.js +2 -61
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +32 -0
- package/dist/commands/dev.js.map +1 -1
- package/dist/server/auth/discovery.d.ts +28 -7
- package/dist/server/auth/discovery.js +16 -11
- package/dist/server/auth/discovery.js.map +1 -1
- package/dist/server/auth/providers/auth0.d.ts +11 -5
- package/dist/server/auth/providers/auth0.js +25 -12
- package/dist/server/auth/providers/auth0.js.map +1 -1
- package/dist/server/auth/providers/auth0.test.js +28 -13
- package/dist/server/auth/providers/auth0.test.js.map +1 -1
- package/dist/server/auth/providers/clerk.d.ts +5 -3
- package/dist/server/auth/providers/clerk.js +5 -7
- package/dist/server/auth/providers/clerk.js.map +1 -1
- package/dist/server/auth/providers/clerk.test.js +4 -25
- package/dist/server/auth/providers/clerk.test.js.map +1 -1
- package/dist/server/auth/providers/custom.d.ts +18 -2
- package/dist/server/auth/providers/custom.js +22 -10
- package/dist/server/auth/providers/custom.js.map +1 -1
- package/dist/server/auth/providers/custom.test.js +41 -4
- package/dist/server/auth/providers/custom.test.js.map +1 -1
- package/dist/server/auth/providers/descope.d.ts +9 -7
- package/dist/server/auth/providers/descope.js +29 -8
- package/dist/server/auth/providers/descope.js.map +1 -1
- package/dist/server/auth/providers/descope.test.js +16 -12
- package/dist/server/auth/providers/descope.test.js.map +1 -1
- package/dist/server/auth/providers/shared.d.ts +2 -0
- package/dist/server/auth/providers/shared.js +6 -0
- package/dist/server/auth/providers/shared.js.map +1 -0
- package/dist/server/auth/providers/shared.test.js +10 -0
- package/dist/server/auth/providers/shared.test.js.map +1 -0
- package/dist/server/auth/providers/stytch.d.ts +2 -1
- package/dist/server/auth/providers/stytch.js +1 -5
- package/dist/server/auth/providers/stytch.js.map +1 -1
- package/dist/server/auth/providers/workos.d.ts +2 -1
- package/dist/server/auth/providers/workos.js +1 -5
- package/dist/server/auth/providers/workos.js.map +1 -1
- package/dist/server/auth/security-schemes.d.ts +23 -0
- package/dist/server/auth/security-schemes.js +64 -0
- package/dist/server/auth/security-schemes.js.map +1 -0
- package/dist/server/auth/security-schemes.test.d.ts +1 -0
- package/dist/server/auth/security-schemes.test.js +99 -0
- package/dist/server/auth/security-schemes.test.js.map +1 -0
- package/dist/server/auth/setup.d.ts +3 -1
- package/dist/server/auth/setup.js +64 -23
- package/dist/server/auth/setup.js.map +1 -1
- package/dist/server/auth/setup.test.js +291 -2
- package/dist/server/auth/setup.test.js.map +1 -1
- package/dist/server/auth/verify.d.ts +3 -2
- package/dist/server/auth/verify.js +2 -1
- package/dist/server/auth/verify.js.map +1 -1
- package/dist/server/auth/verify.test.js +13 -0
- package/dist/server/auth/verify.test.js.map +1 -1
- package/dist/server/host.d.ts +2 -0
- package/dist/server/host.js +11 -0
- package/dist/server/host.js.map +1 -0
- package/dist/server/host.test.d.ts +1 -0
- package/dist/server/host.test.js +13 -0
- package/dist/server/host.test.js.map +1 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/server.d.ts +61 -9
- package/dist/server/server.js +208 -118
- package/dist/server/server.js.map +1 -1
- package/dist/server/skills-integration.test.d.ts +1 -0
- package/dist/server/skills-integration.test.js +63 -0
- package/dist/server/skills-integration.test.js.map +1 -0
- package/dist/server/skills.d.ts +23 -0
- package/dist/server/skills.js +178 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/skills.test.d.ts +1 -0
- package/dist/server/skills.test.js +210 -0
- package/dist/server/skills.test.js.map +1 -0
- package/dist/server/view-name.test-d.d.ts +1 -0
- package/dist/server/view-name.test-d.js +8 -0
- package/dist/server/view-name.test-d.js.map +1 -0
- package/dist/server/view-resource-resolution.test.js +93 -10
- package/dist/server/view-resource-resolution.test.js.map +1 -1
- package/dist/server/viewsDevServer.js +4 -1
- package/dist/server/viewsDevServer.js.map +1 -1
- package/dist/test/view.test.js +70 -102
- package/dist/test/view.test.js.map +1 -1
- package/dist/web/bridges/adaptor.d.ts +51 -0
- package/dist/web/bridges/adaptor.js +330 -0
- package/dist/web/bridges/adaptor.js.map +1 -0
- package/dist/web/bridges/adaptor.test.d.ts +1 -0
- package/dist/web/bridges/adaptor.test.js +208 -0
- package/dist/web/bridges/adaptor.test.js.map +1 -0
- package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
- package/dist/web/bridges/apps-sdk/bridge.js +15 -4
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
- package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
- package/dist/web/bridges/apps-sdk/index.js +0 -1
- package/dist/web/bridges/apps-sdk/index.js.map +1 -1
- package/dist/web/bridges/get-adaptor.d.ts +4 -4
- package/dist/web/bridges/get-adaptor.js +6 -11
- package/dist/web/bridges/get-adaptor.js.map +1 -1
- package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
- package/dist/web/bridges/get-adaptor.test.js +32 -0
- package/dist/web/bridges/get-adaptor.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.d.ts +13 -2
- package/dist/web/bridges/mcp-app/bridge.js +46 -4
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
- package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
- package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/index.d.ts +0 -1
- package/dist/web/bridges/mcp-app/index.js +0 -1
- package/dist/web/bridges/mcp-app/index.js.map +1 -1
- package/dist/web/bridges/mcp-app/view-tools.test.js +5 -6
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
- package/dist/web/bridges/types.d.ts +10 -0
- package/dist/web/bridges/types.js +14 -1
- package/dist/web/bridges/types.js.map +1 -1
- package/dist/web/bridges/types.test.d.ts +1 -0
- package/dist/web/bridges/types.test.js +19 -0
- package/dist/web/bridges/types.test.js.map +1 -0
- package/dist/web/components/modal-provider.d.ts +1 -1
- package/dist/web/components/modal-provider.js +4 -3
- package/dist/web/components/modal-provider.js.map +1 -1
- package/dist/web/create-store.test.js +8 -5
- package/dist/web/create-store.test.js.map +1 -1
- package/dist/web/data-llm.d.ts +1 -1
- package/dist/web/data-llm.test.js +17 -5
- package/dist/web/data-llm.test.js.map +1 -1
- package/dist/web/hooks/use-call-tool.test.js +37 -23
- package/dist/web/hooks/use-call-tool.test.js.map +1 -1
- package/dist/web/hooks/use-display-mode.test.js +56 -20
- package/dist/web/hooks/use-display-mode.test.js.map +1 -1
- package/dist/web/hooks/use-download.test.js +11 -3
- package/dist/web/hooks/use-download.test.js.map +1 -1
- package/dist/web/hooks/use-files.test.js +10 -2
- package/dist/web/hooks/use-files.test.js.map +1 -1
- package/dist/web/hooks/use-layout.test.js +59 -26
- package/dist/web/hooks/use-layout.test.js.map +1 -1
- package/dist/web/hooks/use-open-external.test.js +13 -3
- package/dist/web/hooks/use-open-external.test.js.map +1 -1
- package/dist/web/hooks/use-request-close.test.js +35 -40
- package/dist/web/hooks/use-request-close.test.js.map +1 -1
- package/dist/web/hooks/use-request-modal.test.js +10 -0
- package/dist/web/hooks/use-request-modal.test.js.map +1 -1
- package/dist/web/hooks/use-request-size.test.js +35 -53
- package/dist/web/hooks/use-request-size.test.js.map +1 -1
- package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
- package/dist/web/hooks/use-tool-info.test.js +37 -27
- package/dist/web/hooks/use-tool-info.test.js.map +1 -1
- package/dist/web/hooks/use-user.test.js +81 -35
- package/dist/web/hooks/use-user.test.js.map +1 -1
- package/dist/web/hooks/use-view-state.test.js +6 -2
- package/dist/web/hooks/use-view-state.test.js.map +1 -1
- package/dist/web/plugin/plugin.js +0 -1
- package/dist/web/plugin/plugin.js.map +1 -1
- package/package.json +21 -20
- package/dist/server/auth/providers/stytch.test.js +0 -33
- package/dist/server/auth/providers/stytch.test.js.map +0 -1
- package/dist/server/auth/providers/workos.test.js +0 -41
- package/dist/server/auth/providers/workos.test.js.map +0 -1
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
- package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
- package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
- package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
- package/dist/web/bridges/mcp-app/adaptor.js +0 -283
- package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
- /package/dist/{server/auth/providers/stytch.test.d.ts → cli/build-steps.test.d.ts} +0 -0
- /package/dist/server/auth/providers/{workos.test.d.ts → shared.test.d.ts} +0 -0
package/dist/commands/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveViewsDir } from \"../cli/resolve-views-dir.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, await resolveViewsDir(root));\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from \"@oclif/core\";\nimport { Box, render, Text } from \"ink\";\nimport { resolvePort } from \"../cli/detect-port.js\";\nimport { Header } from \"../cli/header.js\";\nimport { resolveViewsDir } from \"../cli/resolve-views-dir.js\";\nimport { runPlain } from \"../cli/run-plain.js\";\nimport { startTunnelControlServer } from \"../cli/tunnel-control-server.js\";\nimport { useMessages } from \"../cli/use-messages.js\";\nimport { useNodemon } from \"../cli/use-nodemon.js\";\nimport { useOpenBrowser } from \"../cli/use-open-browser.js\";\nimport { useTunnel } from \"../cli/use-tunnel.js\";\nimport { useTypeScriptCheck } from \"../cli/use-typescript-check.js\";\nimport { scanAndWriteViewsDts } from \"../web/plugin/scan-views.js\";\n\nexport default class Dev extends Command {\n static override description = \"Start development server\";\n static override examples = [\"skybridge\"];\n static override flags = {\n port: Flags.integer({\n char: \"p\",\n description: \"Port to run the server on\",\n min: 1,\n }),\n tunnel: Flags.boolean({\n description: \"Open an Alpic tunnel for remote testing\",\n default: false,\n }),\n open: Flags.boolean({\n description: \"Open DevTools in the browser when the server is ready\",\n default: process.env.SKYBRIDGE_OPEN !== \"false\",\n allowNo: true,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Show tunnel logs\",\n default: false,\n }),\n plain: Flags.boolean({\n description:\n \"Disable the interactive UI and stream raw server logs to stdout, so you can pipe them through a formatter (e.g. `skybridge dev --plain | bunyan`).\",\n default: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(Dev);\n\n // Generate .skybridge/views.d.ts before render() spawns `tsc --noEmit\n // --watch`. Vite's plugin config hook writes the same file when nodemon\n // boots the server, but tsc starts in parallel — if .skybridge/ doesn't\n // exist at tsc startup, its watcher never picks up the late-created file\n // and the dev UI reports phantom TS errors forever.\n const root = process.cwd();\n try {\n scanAndWriteViewsDts(root, await resolveViewsDir(root));\n } catch {\n // Best-effort: if the scan fails (e.g. broken vite config, duplicate\n // view names) tsc may show phantom errors, but the dev server should\n // still start so the developer can fix the underlying issue.\n }\n\n const { port, fallback, envWarning } = await resolvePort(flags.port);\n if (envWarning) {\n this.warn(envWarning);\n }\n\n const {\n port: controlPort,\n manager: tunnelManager,\n close: closeTunnelControl,\n } = await startTunnelControlServer(() => port);\n\n const env = {\n ...process.env,\n __PORT: String(port),\n __TUNNEL_CONTROL_PORT: String(controlPort),\n };\n\n if (flags.plain) {\n const teardown = runPlain({\n env,\n port,\n fallback,\n version: this.config.version,\n tunnel: flags.tunnel,\n tunnelManager,\n });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g.\n // nodemon's) exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n teardown();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n return;\n }\n\n const App = () => {\n const tsErrors = useTypeScriptCheck();\n const [messages, pushMessage] = useMessages();\n useNodemon(env, pushMessage);\n useOpenBrowser(port, flags.open);\n const tunnelState = useTunnel(\n port,\n pushMessage,\n flags.verbose,\n flags.tunnel,\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} marginLeft={1}>\n <Header version={this.config.version} />\n\n <Box>\n <Text>🏠{\" \"}</Text>\n {fallback ? (\n <Text color=\"yellow\">3000 in use, running on </Text>\n ) : (\n <Text>Running on </Text>\n )}\n <Text color=\"green\">{`http://localhost:${port}/mcp`}</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test locally with DevTools:{\" \"}\n </Text>\n <Text color=\"green\">{`http://localhost:${port}/`}</Text>\n </Box>\n\n {tunnelState.status === \"idle\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Get a public URL and LLM Playground access with </Text>\n <Text color=\"cyan\" bold>\n --tunnel\n </Text>\n <Text>.</Text>\n </Box>\n )}\n {tunnelState.status === \"starting\" && (\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"yellow\">{tunnelState.message}</Text>\n </Box>\n )}\n {tunnelState.status === \"connected\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text>Exposed on </Text>\n <Text color=\"green\">{`${tunnelState.url}/mcp`}</Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"white\" bold>\n Test with an LLM on Playground:{\" \"}\n </Text>\n <Text color=\"green\">{`${tunnelState.url}/try`}</Text>\n </Box>\n </Box>\n )}\n {tunnelState.status === \"error\" && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text>🌍{\" \"}</Text>\n <Text color=\"red\">\n Cannot open tunnel: {tunnelState.message}\n </Text>\n </Box>\n <Box>\n <Text color=\"#20a832\">→{\" \"}</Text>\n <Text color=\"red\">{`Try manually: npx alpic tunnel --port ${port}`}</Text>\n </Box>\n </Box>\n )}\n\n <Box>\n <Text>🛟{\" \"}</Text>\n <Text>Need help? Reach us on </Text>\n <Text color=\"white\" underline>\n https://discord.alpic.ai\n </Text>\n </Box>\n\n {tsErrors.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"red\" bold>\n ⚠️ TypeScript errors found:\n </Text>\n {tsErrors.map((error) => (\n <Box\n key={`${error.file}:${error.line}:${error.col}`}\n marginLeft={2}\n flexDirection=\"column\"\n >\n <Box>\n <Text color=\"white\">{error.file}</Text>\n <Text color=\"grey\">\n ({error.line},{error.col}):{\" \"}\n </Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"red\">{error.message}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n {messages.length > 0 && (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"white\" bold>\n Logs:\n </Text>\n {messages.map((message) => (\n <Box key={message.id} marginLeft={2}>\n {message.type === \"restart\" ? (\n <>\n <Text color=\"green\">✓{\" \"}</Text>\n <Text color=\"white\">{message.text}</Text>\n </>\n ) : message.type === \"error\" ? (\n <Text color=\"red\">{message.text}</Text>\n ) : (\n <Text>{message.text}</Text>\n )}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n };\n\n // Note: `exitOnCtrlC: false` because we own SIGINT below to guarantee\n // alpic gets killed before we exit. If anything ever calls `useInput` or\n // puts stdin into raw mode, also wire an explicit `\\x03` keypress to the\n // shutdown function — Ink will otherwise swallow Ctrl-C without ever\n // delivering SIGINT.\n const ink = render(<App />, { exitOnCtrlC: false, patchConsole: true });\n\n // Synchronous-first shutdown: kill the alpic subprocess up front so we\n // can't leave it orphaned even if another SIGINT listener (e.g. nodemon's)\n // exits the process before our async cleanup completes.\n const shutdown = (code: number) => () => {\n tunnelManager.stop();\n void closeTunnelControl()\n .catch((err) => {\n console.error(\"Failed to close tunnel control server\", err);\n })\n .finally(() => {\n ink.unmount();\n process.exit(code);\n });\n };\n process.once(\"SIGINT\", shutdown(130));\n process.once(\"SIGTERM\", shutdown(143));\n }\n}\n"]}
|
|
@@ -1,11 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
|
|
4
|
+
* `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
|
|
5
|
+
* we need it for JWKS token verification, so we extend the schema to keep it.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
declare const DiscoverySchema: z.ZodObject<{
|
|
8
|
+
issuer: z.ZodString;
|
|
9
|
+
authorization_endpoint: z.ZodURL;
|
|
10
|
+
token_endpoint: z.ZodURL;
|
|
11
|
+
registration_endpoint: z.ZodOptional<z.ZodURL>;
|
|
12
|
+
scopes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13
|
+
response_types_supported: z.ZodArray<z.ZodString>;
|
|
14
|
+
response_modes_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
|
+
grant_types_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
16
|
+
token_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
|
+
token_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
|
+
service_documentation: z.ZodOptional<z.ZodURL>;
|
|
19
|
+
revocation_endpoint: z.ZodOptional<z.ZodURL>;
|
|
20
|
+
revocation_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
21
|
+
revocation_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
22
|
+
introspection_endpoint: z.ZodOptional<z.ZodString>;
|
|
23
|
+
introspection_endpoint_auth_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
24
|
+
introspection_endpoint_auth_signing_alg_values_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
|
+
code_challenge_methods_supported: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
client_id_metadata_document_supported: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
jwks_uri: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, z.core.$loose>;
|
|
29
|
+
export type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;
|
|
10
30
|
/** Fetches and validates an authorization server's discovery document. */
|
|
11
31
|
export declare function discoverAuthorizationServer(issuer: string): Promise<DiscoveredMetadata>;
|
|
32
|
+
export {};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { OAuthMetadataSchema
|
|
1
|
+
import { OAuthMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's
|
|
5
|
+
* `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but
|
|
6
|
+
* we need it for JWKS token verification, so we extend the schema to keep it.
|
|
7
|
+
*/
|
|
8
|
+
const DiscoverySchema = OAuthMetadataSchema.extend({
|
|
9
|
+
jwks_uri: z.string().optional(),
|
|
10
|
+
});
|
|
2
11
|
const WELL_KNOWN = [
|
|
3
12
|
"/.well-known/openid-configuration",
|
|
4
13
|
"/.well-known/oauth-authorization-server",
|
|
@@ -22,22 +31,18 @@ export async function discoverAuthorizationServer(issuer) {
|
|
|
22
31
|
if (!res.ok) {
|
|
23
32
|
throw new Error(`HTTP ${res.status}`);
|
|
24
33
|
}
|
|
25
|
-
const
|
|
26
|
-
if (!parsed.success) {
|
|
27
|
-
throw new Error(`invalid metadata (${parsed.error.message})`);
|
|
28
|
-
}
|
|
34
|
+
const meta = DiscoverySchema.parse(await res.json());
|
|
29
35
|
// RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).
|
|
30
|
-
if (
|
|
31
|
-
throw new Error(`issuer mismatch: ${
|
|
36
|
+
if (meta.issuer.replace(/\/$/, "") !== base) {
|
|
37
|
+
throw new Error(`issuer mismatch: ${meta.issuer}`);
|
|
32
38
|
}
|
|
33
|
-
const metadata = parsed.data;
|
|
34
39
|
// Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a
|
|
35
40
|
// valid openid-configuration without `registration_endpoint` yet expose
|
|
36
41
|
// it at oauth-authorization-server. Keep looking past a doc that omits it.
|
|
37
|
-
if (
|
|
38
|
-
return
|
|
42
|
+
if (meta.registration_endpoint) {
|
|
43
|
+
return meta;
|
|
39
44
|
}
|
|
40
|
-
fallback ??=
|
|
45
|
+
fallback ??= meta;
|
|
41
46
|
}
|
|
42
47
|
catch (err) {
|
|
43
48
|
errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/server/auth/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAGH,MAAM,UAAU,GAAG;IACjB,mCAAmC;IACnC,yCAAyC;CAC1C,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,QAAwC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,yEAAyE;QACzE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,oBAAoB,CAAC;aAClD,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACrD,yEAAyE;YACzE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,CAAC;YACD,0EAA0E;YAC1E,wEAAwE;YACxE,2EAA2E;YAC3E,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,QAAQ,KAAK,IAAI,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACT,GAAG,GAAG,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import { OAuthMetadataSchema } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { z } from \"zod\";\n\n/**\n * Discovery doc validated as OAuth AS metadata + `jwks_uri`. The SDK's\n * `OAuthMetadataSchema` omits `jwks_uri` (its client never verifies tokens), but\n * we need it for JWKS token verification, so we extend the schema to keep it.\n */\nconst DiscoverySchema = OAuthMetadataSchema.extend({\n jwks_uri: z.string().optional(),\n});\nexport type DiscoveredMetadata = z.infer<typeof DiscoverySchema>;\n\nconst WELL_KNOWN = [\n \"/.well-known/openid-configuration\",\n \"/.well-known/oauth-authorization-server\",\n];\n\nconst DISCOVERY_TIMEOUT_MS = 5000;\n\n/** Fetches and validates an authorization server's discovery document. */\nexport async function discoverAuthorizationServer(\n issuer: string,\n): Promise<DiscoveredMetadata> {\n const base = issuer.replace(/\\/$/, \"\");\n const errors: string[] = [];\n // First valid doc lacking a registration_endpoint, kept as a fallback so a\n // genuinely non-DCR IdP still resolves (and is rejected later by the caller).\n let fallback: DiscoveredMetadata | undefined;\n\n for (const path of WELL_KNOWN) {\n const url = `${base}${path}`;\n // Any failure (network/timeout, non-2xx, non-JSON, invalid metadata, issuer\n // mismatch) records a per-URL reason and falls through to the next path.\n try {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n const meta = DiscoverySchema.parse(await res.json());\n // RFC 8414 §3.3: issuer must match the fetch origin (slash-insensitive).\n if (meta.issuer.replace(/\\/$/, \"\") !== base) {\n throw new Error(`issuer mismatch: ${meta.issuer}`);\n }\n // Prefer the document that advertises DCR: some IdPs (e.g. Clerk) serve a\n // valid openid-configuration without `registration_endpoint` yet expose\n // it at oauth-authorization-server. Keep looking past a doc that omits it.\n if (meta.registration_endpoint) {\n return meta;\n }\n fallback ??= meta;\n } catch (err) {\n errors.push(\n `${url}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (fallback) {\n return fallback;\n }\n throw new Error(`OAuth discovery failed for ${issuer}: ${errors.join(\"; \")}`);\n}\n"]}
|
|
@@ -2,11 +2,17 @@ import type { OAuthConfig } from "../index.js";
|
|
|
2
2
|
import { type CustomProviderOptions } from "./custom.js";
|
|
3
3
|
/**
|
|
4
4
|
* OAuth provider for Auth0. `domain` is the tenant domain (e.g.
|
|
5
|
-
* `acme.us.auth0.com`)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* `acme.us.auth0.com`); `audience` is the API Identifier; `serverUrl` is this
|
|
6
|
+
* server's public URL. Requires DCR enabled on the tenant.
|
|
7
|
+
*
|
|
8
|
+
* Auth0 can't use the client's resource indicator — `audience` must be *in* the
|
|
9
|
+
* authorize request. So it runs as skybridge-as-AS (`serverUrl`, see
|
|
10
|
+
* {@link customProvider}) and bakes `?audience=<id>` into the advertised
|
|
11
|
+
* `authorization_endpoint`. The token's `aud` is the API; `verify.issuer` stays
|
|
12
|
+
* Auth0 (the token's real `iss`).
|
|
9
13
|
*/
|
|
10
14
|
export declare function auth0Provider(opts: {
|
|
11
15
|
domain: string;
|
|
12
|
-
|
|
16
|
+
audience: string;
|
|
17
|
+
serverUrl: string;
|
|
18
|
+
} & Omit<CustomProviderOptions, "issuer" | "audience" | "baseUrl" | "serverUrl">): Promise<OAuthConfig>;
|
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
import { customProvider } from "./custom.js";
|
|
2
|
-
|
|
3
|
-
function toIssuerUrl(domain) {
|
|
4
|
-
const withScheme = /^https?:\/\//.test(domain) ? domain : `https://${domain}`;
|
|
5
|
-
return withScheme.replace(/\/$/, "");
|
|
6
|
-
}
|
|
2
|
+
import { toIssuerUrl } from "./shared.js";
|
|
7
3
|
/**
|
|
8
4
|
* OAuth provider for Auth0. `domain` is the tenant domain (e.g.
|
|
9
|
-
* `acme.us.auth0.com`)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* `acme.us.auth0.com`); `audience` is the API Identifier; `serverUrl` is this
|
|
6
|
+
* server's public URL. Requires DCR enabled on the tenant.
|
|
7
|
+
*
|
|
8
|
+
* Auth0 can't use the client's resource indicator — `audience` must be *in* the
|
|
9
|
+
* authorize request. So it runs as skybridge-as-AS (`serverUrl`, see
|
|
10
|
+
* {@link customProvider}) and bakes `?audience=<id>` into the advertised
|
|
11
|
+
* `authorization_endpoint`. The token's `aud` is the API; `verify.issuer` stays
|
|
12
|
+
* Auth0 (the token's real `iss`).
|
|
13
13
|
*/
|
|
14
|
-
export function auth0Provider(opts) {
|
|
15
|
-
const { domain, ...rest } = opts;
|
|
16
|
-
|
|
14
|
+
export async function auth0Provider(opts) {
|
|
15
|
+
const { domain, audience, ...rest } = opts;
|
|
16
|
+
const config = await customProvider({
|
|
17
|
+
issuer: toIssuerUrl(domain),
|
|
18
|
+
audience,
|
|
19
|
+
...rest,
|
|
20
|
+
});
|
|
21
|
+
const authUrl = new URL(config.oauthMetadata.authorization_endpoint);
|
|
22
|
+
authUrl.searchParams.set("audience", audience);
|
|
23
|
+
return {
|
|
24
|
+
...config,
|
|
25
|
+
oauthMetadata: {
|
|
26
|
+
...config.oauthMetadata,
|
|
27
|
+
authorization_endpoint: authUrl.href,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
17
30
|
}
|
|
18
31
|
//# sourceMappingURL=auth0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth0.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/auth0.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"auth0.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/auth0.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAGC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,QAAQ;QACR,GAAG,IAAI;KACR,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IACrE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO;QACL,GAAG,MAAM;QACT,aAAa,EAAE;YACb,GAAG,MAAM,CAAC,aAAa;YACvB,sBAAsB,EAAE,OAAO,CAAC,IAAI;SACrC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * OAuth provider for Auth0. `domain` is the tenant domain (e.g.\n * `acme.us.auth0.com`); `audience` is the API Identifier; `serverUrl` is this\n * server's public URL. Requires DCR enabled on the tenant.\n *\n * Auth0 can't use the client's resource indicator — `audience` must be *in* the\n * authorize request. So it runs as skybridge-as-AS (`serverUrl`, see\n * {@link customProvider}) and bakes `?audience=<id>` into the advertised\n * `authorization_endpoint`. The token's `aud` is the API; `verify.issuer` stays\n * Auth0 (the token's real `iss`).\n */\nexport async function auth0Provider(\n opts: { domain: string; audience: string; serverUrl: string } & Omit<\n CustomProviderOptions,\n \"issuer\" | \"audience\" | \"baseUrl\" | \"serverUrl\"\n >,\n): Promise<OAuthConfig> {\n const { domain, audience, ...rest } = opts;\n const config = await customProvider({\n issuer: toIssuerUrl(domain),\n audience,\n ...rest,\n });\n const authUrl = new URL(config.oauthMetadata.authorization_endpoint);\n authUrl.searchParams.set(\"audience\", audience);\n return {\n ...config,\n oauthMetadata: {\n ...config.oauthMetadata,\n authorization_endpoint: authUrl.href,\n },\n };\n}\n"]}
|
|
@@ -2,32 +2,47 @@
|
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { auth0Provider } from "./auth0.js";
|
|
4
4
|
afterEach(() => vi.restoreAllMocks());
|
|
5
|
-
function
|
|
5
|
+
function doc(issuer) {
|
|
6
6
|
return {
|
|
7
7
|
issuer,
|
|
8
8
|
authorization_endpoint: `${issuer}/authorize`,
|
|
9
9
|
token_endpoint: `${issuer}/oauth/token`,
|
|
10
10
|
registration_endpoint: `${issuer}/oidc/register`,
|
|
11
11
|
response_types_supported: ["code"],
|
|
12
|
-
scopes_supported: ["openid"],
|
|
12
|
+
scopes_supported: ["openid", "profile", "email"],
|
|
13
13
|
jwks_uri: `${issuer}/.well-known/jwks.json`,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
function mockDiscovery(issuer) {
|
|
17
|
-
return vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify(discoveryDoc(issuer)), {
|
|
18
|
-
headers: { "content-type": "application/json" },
|
|
19
|
-
}));
|
|
20
|
-
}
|
|
21
16
|
describe("auth0Provider", () => {
|
|
22
|
-
it("
|
|
23
|
-
const
|
|
17
|
+
it("advertises skybridge as the AS (static issuer) and bakes audience; verifies against Auth0", async () => {
|
|
18
|
+
const issuer = "https://acme.us.auth0.com";
|
|
19
|
+
vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify(doc(issuer)), {
|
|
20
|
+
headers: { "content-type": "application/json" },
|
|
21
|
+
}));
|
|
24
22
|
const config = await auth0Provider({
|
|
25
23
|
domain: "acme.us.auth0.com",
|
|
26
|
-
audience: "https://
|
|
24
|
+
audience: "https://api.example.com/",
|
|
25
|
+
serverUrl: "https://app.example.com/",
|
|
26
|
+
scopes: ["openid", "profile", "email"],
|
|
27
27
|
});
|
|
28
|
-
|
|
29
|
-
expect(config.
|
|
30
|
-
|
|
28
|
+
// skybridge is the advertised AS: static issuer = serverUrl (trailing slash stripped).
|
|
29
|
+
expect(config.oauthMetadata.issuer).toBe("https://app.example.com");
|
|
30
|
+
// AS metadata scopes match the advertised set (clients read scopes from here).
|
|
31
|
+
expect(config.oauthMetadata.scopes_supported).toEqual([
|
|
32
|
+
"openid",
|
|
33
|
+
"profile",
|
|
34
|
+
"email",
|
|
35
|
+
]);
|
|
36
|
+
expect(config.scopesSupported).toEqual(["openid", "profile", "email"]);
|
|
37
|
+
// audience baked into the advertised authorize endpoint (still pointing at Auth0).
|
|
38
|
+
const url = new URL(config.oauthMetadata.authorization_endpoint);
|
|
39
|
+
expect(url.origin + url.pathname).toBe(`${issuer}/authorize`);
|
|
40
|
+
expect(url.searchParams.get("audience")).toBe("https://api.example.com/");
|
|
41
|
+
// baseUrl left unset so the PRM resource resolves per request (Alpic-safe).
|
|
42
|
+
expect(config.baseUrl).toBeUndefined();
|
|
43
|
+
// token verification still uses Auth0 as issuer + the API audience.
|
|
44
|
+
expect(config.verify.issuer).toBe(issuer);
|
|
45
|
+
expect(config.verify.audience).toBe("https://api.example.com/");
|
|
31
46
|
});
|
|
32
47
|
});
|
|
33
48
|
//# sourceMappingURL=auth0.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth0.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/auth0.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,
|
|
1
|
+
{"version":3,"file":"auth0.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/auth0.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,GAAG,CAAC,MAAc;IACzB,OAAO;QACL,MAAM;QACN,sBAAsB,EAAE,GAAG,MAAM,YAAY;QAC7C,cAAc,EAAE,GAAG,MAAM,cAAc;QACvC,qBAAqB,EAAE,GAAG,MAAM,gBAAgB;QAChD,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC;QAChD,QAAQ,EAAE,GAAG,MAAM,wBAAwB;KAC5C,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,2FAA2F,EAAE,KAAK,IAAI,EAAE;QACzG,MAAM,MAAM,GAAG,2BAA2B,CAAC;QAC3C,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,iBAAiB,CAC7C,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE;YACxC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;YACjC,MAAM,EAAE,mBAAmB;YAC3B,QAAQ,EAAE,0BAA0B;YACpC,SAAS,EAAE,0BAA0B;YACrC,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC;SACvC,CAAC,CAAC;QAEH,uFAAuF;QACvF,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACpE,+EAA+E;QAC/E,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC;YACpD,QAAQ;YACR,SAAS;YACT,OAAO;SACR,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QACvE,mFAAmF;QACnF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC;QAC9D,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1E,4EAA4E;QAC5E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;QACvC,oEAAoE;QACpE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment node\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { auth0Provider } from \"./auth0.js\";\n\nafterEach(() => vi.restoreAllMocks());\n\nfunction doc(issuer: string) {\n return {\n issuer,\n authorization_endpoint: `${issuer}/authorize`,\n token_endpoint: `${issuer}/oauth/token`,\n registration_endpoint: `${issuer}/oidc/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"profile\", \"email\"],\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n };\n}\n\ndescribe(\"auth0Provider\", () => {\n it(\"advertises skybridge as the AS (static issuer) and bakes audience; verifies against Auth0\", async () => {\n const issuer = \"https://acme.us.auth0.com\";\n vi.spyOn(globalThis, \"fetch\").mockResolvedValue(\n new Response(JSON.stringify(doc(issuer)), {\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n\n const config = await auth0Provider({\n domain: \"acme.us.auth0.com\",\n audience: \"https://api.example.com/\",\n serverUrl: \"https://app.example.com/\",\n scopes: [\"openid\", \"profile\", \"email\"],\n });\n\n // skybridge is the advertised AS: static issuer = serverUrl (trailing slash stripped).\n expect(config.oauthMetadata.issuer).toBe(\"https://app.example.com\");\n // AS metadata scopes match the advertised set (clients read scopes from here).\n expect(config.oauthMetadata.scopes_supported).toEqual([\n \"openid\",\n \"profile\",\n \"email\",\n ]);\n expect(config.scopesSupported).toEqual([\"openid\", \"profile\", \"email\"]);\n // audience baked into the advertised authorize endpoint (still pointing at Auth0).\n const url = new URL(config.oauthMetadata.authorization_endpoint);\n expect(url.origin + url.pathname).toBe(`${issuer}/authorize`);\n expect(url.searchParams.get(\"audience\")).toBe(\"https://api.example.com/\");\n // baseUrl left unset so the PRM resource resolves per request (Alpic-safe).\n expect(config.baseUrl).toBeUndefined();\n // token verification still uses Auth0 as issuer + the API audience.\n expect(config.verify.issuer).toBe(issuer);\n expect(config.verify.audience).toBe(\"https://api.example.com/\");\n });\n});\n"]}
|
|
@@ -4,9 +4,11 @@ import { type CustomProviderOptions } from "./custom.js";
|
|
|
4
4
|
* OAuth provider for Clerk. `domain` is the Frontend API URL (e.g.
|
|
5
5
|
* `acme.clerk.accounts.dev`, or a production custom domain). Requires Dynamic
|
|
6
6
|
* Client Registration enabled on the instance, and the OAuth application set to
|
|
7
|
-
* issue JWT access tokens (opaque tokens can't be JWKS-verified).
|
|
8
|
-
*
|
|
7
|
+
* issue JWT access tokens (opaque tokens can't be JWKS-verified).
|
|
8
|
+
*
|
|
9
|
+
* Clerk access tokens carry no `aud` claim, so there is no `audience` option —
|
|
10
|
+
* verification is issuer + JWKS only (matching Clerk's own `mcpAuthClerk`).
|
|
9
11
|
*/
|
|
10
12
|
export declare function clerkProvider(opts: {
|
|
11
13
|
domain: string;
|
|
12
|
-
} & Omit<CustomProviderOptions, "issuer">): Promise<OAuthConfig>;
|
|
14
|
+
} & Omit<CustomProviderOptions, "issuer" | "audience">): Promise<OAuthConfig>;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { customProvider } from "./custom.js";
|
|
2
|
-
|
|
3
|
-
function toIssuerUrl(domain) {
|
|
4
|
-
const withScheme = /^https?:\/\//.test(domain) ? domain : `https://${domain}`;
|
|
5
|
-
return withScheme.replace(/\/$/, "");
|
|
6
|
-
}
|
|
2
|
+
import { toIssuerUrl } from "./shared.js";
|
|
7
3
|
/**
|
|
8
4
|
* OAuth provider for Clerk. `domain` is the Frontend API URL (e.g.
|
|
9
5
|
* `acme.clerk.accounts.dev`, or a production custom domain). Requires Dynamic
|
|
10
6
|
* Client Registration enabled on the instance, and the OAuth application set to
|
|
11
|
-
* issue JWT access tokens (opaque tokens can't be JWKS-verified).
|
|
12
|
-
*
|
|
7
|
+
* issue JWT access tokens (opaque tokens can't be JWKS-verified).
|
|
8
|
+
*
|
|
9
|
+
* Clerk access tokens carry no `aud` claim, so there is no `audience` option —
|
|
10
|
+
* verification is issuer + JWKS only (matching Clerk's own `mcpAuthClerk`).
|
|
13
11
|
*/
|
|
14
12
|
export function clerkProvider(opts) {
|
|
15
13
|
const { domain, ...rest } = opts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,cAAc,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA6E;IAE7E,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import type { OAuthConfig } from \"../index.js\";\nimport { type CustomProviderOptions, customProvider } from \"./custom.js\";\nimport { toIssuerUrl } from \"./shared.js\";\n\n/**\n * OAuth provider for Clerk. `domain` is the Frontend API URL (e.g.\n * `acme.clerk.accounts.dev`, or a production custom domain). Requires Dynamic\n * Client Registration enabled on the instance, and the OAuth application set to\n * issue JWT access tokens (opaque tokens can't be JWKS-verified).\n *\n * Clerk access tokens carry no `aud` claim, so there is no `audience` option —\n * verification is issuer + JWKS only (matching Clerk's own `mcpAuthClerk`).\n */\nexport function clerkProvider(\n opts: { domain: string } & Omit<CustomProviderOptions, \"issuer\" | \"audience\">,\n): Promise<OAuthConfig> {\n const { domain, ...rest } = opts;\n return customProvider({ issuer: toIssuerUrl(domain), ...rest });\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { clerkProvider } from "./clerk.js";
|
|
4
4
|
afterEach(() => vi.restoreAllMocks());
|
|
5
|
-
function doc(issuer
|
|
5
|
+
function doc(issuer) {
|
|
6
6
|
return {
|
|
7
7
|
issuer,
|
|
8
8
|
authorization_endpoint: `${issuer}/oauth/authorize`,
|
|
@@ -11,39 +11,18 @@ function doc(issuer, extra = {}) {
|
|
|
11
11
|
response_types_supported: ["code"],
|
|
12
12
|
scopes_supported: ["profile", "email"],
|
|
13
13
|
jwks_uri: `${issuer}/.well-known/jwks.json`,
|
|
14
|
-
...extra,
|
|
15
14
|
};
|
|
16
15
|
}
|
|
17
16
|
describe("clerkProvider", () => {
|
|
18
|
-
it("
|
|
17
|
+
it("verifies issuer + JWKS with no audience (Clerk tokens carry no aud)", async () => {
|
|
19
18
|
const issuer = "https://acme.clerk.accounts.dev";
|
|
20
19
|
const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response(JSON.stringify(doc(issuer)), {
|
|
21
20
|
headers: { "content-type": "application/json" },
|
|
22
21
|
}));
|
|
23
|
-
const config = await clerkProvider({
|
|
24
|
-
domain: "acme.clerk.accounts.dev",
|
|
25
|
-
audience: "my-oauth-app",
|
|
26
|
-
});
|
|
22
|
+
const config = await clerkProvider({ domain: "acme.clerk.accounts.dev" });
|
|
27
23
|
expect(fetchSpy).toHaveBeenCalledWith(`${issuer}/.well-known/openid-configuration`, expect.anything());
|
|
28
24
|
expect(config.verify.issuer).toBe(issuer);
|
|
29
|
-
expect(config.verify.audience).
|
|
30
|
-
});
|
|
31
|
-
it("uses oauth-authorization-server when oidc omits the registration_endpoint", async () => {
|
|
32
|
-
const issuer = "https://acme.clerk.accounts.dev";
|
|
33
|
-
vi.spyOn(globalThis, "fetch").mockImplementation(async (input) => {
|
|
34
|
-
const url = String(input);
|
|
35
|
-
if (url.endsWith("/.well-known/openid-configuration")) {
|
|
36
|
-
return new Response(JSON.stringify(doc(issuer, { registration_endpoint: undefined })), { headers: { "content-type": "application/json" } });
|
|
37
|
-
}
|
|
38
|
-
return new Response(JSON.stringify(doc(issuer)), {
|
|
39
|
-
headers: { "content-type": "application/json" },
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
const config = await clerkProvider({
|
|
43
|
-
domain: "acme.clerk.accounts.dev",
|
|
44
|
-
audience: "my-oauth-app",
|
|
45
|
-
});
|
|
46
|
-
expect(config.oauthMetadata.registration_endpoint).toBe(`${issuer}/oauth/register`);
|
|
25
|
+
expect(config.verify.audience).toBeUndefined();
|
|
47
26
|
});
|
|
48
27
|
});
|
|
49
28
|
//# sourceMappingURL=clerk.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clerk.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,GAAG,CAAC,MAAc
|
|
1
|
+
{"version":3,"file":"clerk.test.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/clerk.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,SAAS,GAAG,CAAC,MAAc;IACzB,OAAO;QACL,MAAM;QACN,sBAAsB,EAAE,GAAG,MAAM,kBAAkB;QACnD,cAAc,EAAE,GAAG,MAAM,cAAc;QACvC,qBAAqB,EAAE,GAAG,MAAM,iBAAiB;QACjD,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,gBAAgB,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;QACtC,QAAQ,EAAE,GAAG,MAAM,wBAAwB;KAC5C,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,iCAAiC,CAAC;QACjD,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,iBAAiB,CAC9D,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE;YACxC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAE1E,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,GAAG,MAAM,mCAAmC,EAC5C,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment node\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { clerkProvider } from \"./clerk.js\";\n\nafterEach(() => vi.restoreAllMocks());\n\nfunction doc(issuer: string) {\n return {\n issuer,\n authorization_endpoint: `${issuer}/oauth/authorize`,\n token_endpoint: `${issuer}/oauth/token`,\n registration_endpoint: `${issuer}/oauth/register`,\n response_types_supported: [\"code\"],\n scopes_supported: [\"profile\", \"email\"],\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n };\n}\n\ndescribe(\"clerkProvider\", () => {\n it(\"verifies issuer + JWKS with no audience (Clerk tokens carry no aud)\", async () => {\n const issuer = \"https://acme.clerk.accounts.dev\";\n const fetchSpy = vi.spyOn(globalThis, \"fetch\").mockResolvedValue(\n new Response(JSON.stringify(doc(issuer)), {\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n\n const config = await clerkProvider({ domain: \"acme.clerk.accounts.dev\" });\n\n expect(fetchSpy).toHaveBeenCalledWith(\n `${issuer}/.well-known/openid-configuration`,\n expect.anything(),\n );\n expect(config.verify.issuer).toBe(issuer);\n expect(config.verify.audience).toBeUndefined();\n });\n});\n"]}
|
|
@@ -3,12 +3,28 @@ import type { OAuthConfig } from "../index.js";
|
|
|
3
3
|
/** Options accepted by {@link customProvider} and the branded providers. */
|
|
4
4
|
export type CustomProviderOptions = {
|
|
5
5
|
issuer: string;
|
|
6
|
-
audience
|
|
6
|
+
/** Expected token `aud`. Omit to skip audience verification — only for IdPs
|
|
7
|
+
* that don't bind an audience (e.g. Clerk). Branded providers whose IdP does
|
|
8
|
+
* bind an audience re-require it in their own options. */
|
|
9
|
+
audience?: string;
|
|
7
10
|
/** Omit to let the server infer the resource origin from request headers. */
|
|
8
11
|
baseUrl?: string;
|
|
12
|
+
/** Advertise THIS server as the authorization server (skybridge-as-AS): the
|
|
13
|
+
* served AS metadata `issuer` and the PRM `authorization_servers` use this URL
|
|
14
|
+
* instead of the IdP's. Needed when skybridge must sit in the auth path — Auth0
|
|
15
|
+
* (the `audience` must be baked into `/authorize`) or the Alpic DCR proxy (Alpic
|
|
16
|
+
* injects the registration endpoint). Use the static public URL; `verify.issuer`
|
|
17
|
+
* stays the IdP (the token's real `iss`). */
|
|
18
|
+
serverUrl?: string;
|
|
19
|
+
/** Advertise this URL as the authorization server (served AS metadata `issuer`
|
|
20
|
+
* and PRM `authorization_servers`) while `verify.issuer` stays the IdP's `iss`.
|
|
21
|
+
* Use when DCR/authorize/token live at a different URL than the token issuer
|
|
22
|
+
* (e.g. Descope's agentic URL vs. its base-project issuer). `serverUrl` wins if
|
|
23
|
+
* both are set. */
|
|
24
|
+
authorizationServer?: string;
|
|
9
25
|
scopes?: string[];
|
|
10
26
|
requiredScopes?: string[];
|
|
11
27
|
metadataOverrides?: Omit<Partial<OAuthMetadata>, "issuer">;
|
|
12
28
|
};
|
|
13
|
-
/** Builds a complete {@link OAuthConfig}
|
|
29
|
+
/** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */
|
|
14
30
|
export declare function customProvider(opts: CustomProviderOptions): Promise<OAuthConfig>;
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import { discoverAuthorizationServer, } from "../discovery.js";
|
|
2
|
-
/** Builds a complete {@link OAuthConfig}
|
|
2
|
+
/** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */
|
|
3
3
|
export async function customProvider(opts) {
|
|
4
4
|
const discovered = await discoverAuthorizationServer(opts.issuer);
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
5
|
+
// JWKS verification needs a signing-key URL; without it the server can't verify
|
|
6
|
+
// tokens. (`registration_endpoint` is optional per RFC 8414 — a no-DCR IdP simply
|
|
7
|
+
// omits it; a proxy like Alpic, or pre-registered clients, supply registration.)
|
|
9
8
|
if (!discovered.jwks_uri) {
|
|
10
9
|
throw new Error(`${opts.issuer} discovery has no jwks_uri; JWKS verification requires it.`);
|
|
11
10
|
}
|
|
12
|
-
// Overrides adjust only advertised metadata (
|
|
13
|
-
//
|
|
14
|
-
const { issuer: _issuer, jwks_uri: _jwks, ...overrides } =
|
|
15
|
-
const
|
|
11
|
+
// Overrides adjust only advertised metadata; the trust anchor (issuer, jwks_uri)
|
|
12
|
+
// always comes from validated discovery.
|
|
13
|
+
const { issuer: _issuer, jwks_uri: _jwks, ...overrides } = opts.metadataOverrides ?? {};
|
|
14
|
+
const base = { ...discovered, ...overrides };
|
|
15
|
+
const scopesSupported = opts.scopes ?? base.scopes_supported;
|
|
16
|
+
// serverUrl (skybridge-as-AS) or authorizationServer (a distinct AS URL)
|
|
17
|
+
// override the advertised issuer (and keep the served scopes in sync). The
|
|
18
|
+
// verifier still trusts the IdP's `iss`. serverUrl wins when both are set.
|
|
19
|
+
const advertisedIssuer = opts.serverUrl?.replace(/\/$/, "") ??
|
|
20
|
+
opts.authorizationServer?.replace(/\/$/, "");
|
|
21
|
+
const oauthMetadata = advertisedIssuer
|
|
22
|
+
? {
|
|
23
|
+
...base,
|
|
24
|
+
issuer: advertisedIssuer,
|
|
25
|
+
scopes_supported: scopesSupported,
|
|
26
|
+
}
|
|
27
|
+
: base;
|
|
16
28
|
return {
|
|
17
29
|
baseUrl: opts.baseUrl,
|
|
18
30
|
oauthMetadata,
|
|
@@ -21,7 +33,7 @@ export async function customProvider(opts) {
|
|
|
21
33
|
audience: opts.audience,
|
|
22
34
|
jwksUri: discovered.jwks_uri,
|
|
23
35
|
},
|
|
24
|
-
scopesSupported
|
|
36
|
+
scopesSupported,
|
|
25
37
|
requiredScopes: opts.requiredScopes,
|
|
26
38
|
};
|
|
27
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/custom.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../../../src/server/auth/providers/custom.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AA8BzB,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAA2B;IAE3B,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAElE,gFAAgF;IAChF,kFAAkF;IAClF,iFAAiF;IACjF,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,MAAM,4DAA4D,CAC3E,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,yCAAyC;IACzC,MAAM,EACJ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,KAAK,EACf,GAAG,SAAS,EACb,GAAgC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC9D,MAAM,IAAI,GAAuB,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,EAAE,CAAC;IACjE,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC;IAE7D,yEAAyE;IACzE,2EAA2E;IAC3E,2EAA2E;IAC3E,MAAM,gBAAgB,GACpB,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAuB,gBAAgB;QACxD,CAAC,CAAC;YACE,GAAG,IAAI;YACP,MAAM,EAAE,gBAAgB;YACxB,gBAAgB,EAAE,eAAe;SAClC;QACH,CAAC,CAAC,IAAI,CAAC;IAET,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa;QACb,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,UAAU,CAAC,QAAQ;SAC7B;QACD,eAAe;QACf,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type { OAuthMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport {\n type DiscoveredMetadata,\n discoverAuthorizationServer,\n} from \"../discovery.js\";\nimport type { OAuthConfig } from \"../index.js\";\n\n/** Options accepted by {@link customProvider} and the branded providers. */\nexport type CustomProviderOptions = {\n issuer: string;\n /** Expected token `aud`. Omit to skip audience verification — only for IdPs\n * that don't bind an audience (e.g. Clerk). Branded providers whose IdP does\n * bind an audience re-require it in their own options. */\n audience?: string;\n /** Omit to let the server infer the resource origin from request headers. */\n baseUrl?: string;\n /** Advertise THIS server as the authorization server (skybridge-as-AS): the\n * served AS metadata `issuer` and the PRM `authorization_servers` use this URL\n * instead of the IdP's. Needed when skybridge must sit in the auth path — Auth0\n * (the `audience` must be baked into `/authorize`) or the Alpic DCR proxy (Alpic\n * injects the registration endpoint). Use the static public URL; `verify.issuer`\n * stays the IdP (the token's real `iss`). */\n serverUrl?: string;\n /** Advertise this URL as the authorization server (served AS metadata `issuer`\n * and PRM `authorization_servers`) while `verify.issuer` stays the IdP's `iss`.\n * Use when DCR/authorize/token live at a different URL than the token issuer\n * (e.g. Descope's agentic URL vs. its base-project issuer). `serverUrl` wins if\n * both are set. */\n authorizationServer?: string;\n scopes?: string[];\n requiredScopes?: string[];\n metadataOverrides?: Omit<Partial<OAuthMetadata>, \"issuer\">;\n};\n\n/** Builds a complete {@link OAuthConfig} from an IdP's OAuth discovery document. */\nexport async function customProvider(\n opts: CustomProviderOptions,\n): Promise<OAuthConfig> {\n const discovered = await discoverAuthorizationServer(opts.issuer);\n\n // JWKS verification needs a signing-key URL; without it the server can't verify\n // tokens. (`registration_endpoint` is optional per RFC 8414 — a no-DCR IdP simply\n // omits it; a proxy like Alpic, or pre-registered clients, supply registration.)\n if (!discovered.jwks_uri) {\n throw new Error(\n `${opts.issuer} discovery has no jwks_uri; JWKS verification requires it.`,\n );\n }\n\n // Overrides adjust only advertised metadata; the trust anchor (issuer, jwks_uri)\n // always comes from validated discovery.\n const {\n issuer: _issuer,\n jwks_uri: _jwks,\n ...overrides\n }: Partial<DiscoveredMetadata> = opts.metadataOverrides ?? {};\n const base: DiscoveredMetadata = { ...discovered, ...overrides };\n const scopesSupported = opts.scopes ?? base.scopes_supported;\n\n // serverUrl (skybridge-as-AS) or authorizationServer (a distinct AS URL)\n // override the advertised issuer (and keep the served scopes in sync). The\n // verifier still trusts the IdP's `iss`. serverUrl wins when both are set.\n const advertisedIssuer =\n opts.serverUrl?.replace(/\\/$/, \"\") ??\n opts.authorizationServer?.replace(/\\/$/, \"\");\n const oauthMetadata: DiscoveredMetadata = advertisedIssuer\n ? {\n ...base,\n issuer: advertisedIssuer,\n scopes_supported: scopesSupported,\n }\n : base;\n\n return {\n baseUrl: opts.baseUrl,\n oauthMetadata,\n verify: {\n issuer: discovered.issuer,\n audience: opts.audience,\n jwksUri: discovered.jwks_uri,\n },\n scopesSupported,\n requiredScopes: opts.requiredScopes,\n };\n}\n"]}
|