@cyanmycelium/mcp-broker 0.4.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp-broker.example/CONFIGURATION-EN.md +861 -0
- package/.mcp-broker.example/CONFIGURATION-FR.md +871 -0
- package/.mcp-broker.example/README.md +8 -3
- package/.mcp-broker.example/config.json +86 -0
- package/README.md +122 -3
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +180 -208
- package/dist/bin.js.map +1 -1
- package/dist/chunk-FTDKH2C4.js +3670 -0
- package/dist/chunk-FTDKH2C4.js.map +1 -0
- package/dist/{broker/grammars → grammars}/claude/en.json +1 -1
- package/dist/{broker/grammars → grammars}/claude/fr.json +1 -1
- package/dist/index.d.ts +1790 -18
- package/dist/index.js +2 -14
- package/dist/index.js.map +1 -1
- package/package.json +14 -8
- package/scripts/copy-assets.mjs +16 -10
- package/scripts/gen-cert.mjs +5 -5
- package/scripts/pack-mcpb.mjs +5 -5
- package/scripts/sign-bundle.mjs +6 -6
- package/src/auth/auth.config.ts +98 -0
- package/src/auth/auth.types.ts +120 -0
- package/src/auth/http.auth.ts +128 -0
- package/src/auth/index.ts +34 -0
- package/src/auth/jwt.validator.ts +63 -0
- package/src/auth/provider.auth.ts +114 -0
- package/src/auth/resource.metadata.ts +34 -0
- package/src/authorization/audit.ts +35 -0
- package/src/authorization/capability.classifier.ts +114 -0
- package/src/authorization/index.ts +37 -0
- package/src/authorization/policy.engine.ts +212 -0
- package/src/authorization/policy.types.ts +105 -0
- package/src/authorization/resource.path.ts +126 -0
- package/src/authorization/runtime.ts +56 -0
- package/src/authorization/slot.resource.ts +50 -0
- package/src/authorization/subject.mapper.ts +81 -0
- package/src/bin.ts +90 -7
- package/src/broker/adapters/broker.adapter.info.ts +3 -3
- package/src/broker/adapters/broker.adapter.providers.ts +3 -3
- package/src/broker/aggregate/aggregate.catalog.ts +49 -21
- package/src/broker/aggregate/aggregate.server.ts +149 -19
- package/src/broker/aggregate/provider.client.session.ts +22 -22
- package/src/broker/behaviors/broker.behavior.info.ts +4 -4
- package/src/broker/behaviors/broker.behavior.providers.ts +6 -6
- package/src/broker/broker.context.ts +10 -4
- package/src/broker/broker.grammars.ts +16 -13
- package/src/broker/broker.server.ts +12 -9
- package/src/broker/grammars/claude/en.json +1 -1
- package/src/broker/grammars/claude/fr.json +1 -1
- package/src/broker/index.ts +9 -9
- package/src/config.ts +81 -8
- package/src/index.ts +121 -20
- package/src/{mcpb.loader.ts → mcpb/mcpb.loader.ts} +24 -21
- package/src/{mcpb.unzip.ts → mcpb/mcpb.unzip.ts} +2 -2
- package/src/remote.transports.ts +11 -8
- package/src/remote.upstream.ts +11 -8
- package/src/stdio.upstream.ts +9 -6
- package/src/upstream.ts +6 -3
- package/src/ws/ws.interfaces.ts +357 -0
- package/src/{ws.tunnel.builder.ts → ws/ws.tunnel.builder.ts} +112 -9
- package/src/{ws.tunnel.ts → ws/ws.tunnel.ts} +646 -457
- package/web/README.md +94 -0
- package/web/assets/logo.png +0 -0
- package/web/broker-self-mcp.html +338 -0
- package/web/css/styles.css +580 -0
- package/web/demos/DemoPlaceholder.html +258 -0
- package/web/demos/broker-explorer/css/app.css +393 -0
- package/web/demos/broker-explorer/index.html +94 -0
- package/web/demos/broker-explorer/js/app.js +271 -0
- package/web/demos/broker-explorer/js/mcp-ws-client.js +132 -0
- package/web/demos/oauth-lab/README.md +94 -0
- package/web/demos/oauth-lab/config.json +117 -0
- package/web/demos/oauth-lab/css/app.css +1097 -0
- package/web/demos/oauth-lab/index.html +323 -0
- package/web/demos/oauth-lab/js/app.js +654 -0
- package/web/demos/oauth-lab/server/auth-server.mjs +426 -0
- package/web/demos/oauth-lab/server/factory-provider.mjs +269 -0
- package/web/demos/oauth-lab/server/smoke-test.mjs +308 -0
- package/web/demos/oauth-lab/server/start.mjs +106 -0
- package/web/demos/provider-tunnel/css/app.css +384 -0
- package/web/demos/provider-tunnel/index.html +99 -0
- package/web/demos/provider-tunnel/js/app.js +226 -0
- package/web/demos/provider-tunnel/js/toolbox-server.js +186 -0
- package/web/index.html +558 -0
- package/web/js/lib/broker-tunnel.js +173 -0
- package/dist/broker/adapters/broker.adapter.info.d.ts +0 -16
- package/dist/broker/adapters/broker.adapter.info.js +0 -43
- package/dist/broker/adapters/broker.adapter.info.js.map +0 -1
- package/dist/broker/adapters/broker.adapter.providers.d.ts +0 -18
- package/dist/broker/adapters/broker.adapter.providers.js +0 -61
- package/dist/broker/adapters/broker.adapter.providers.js.map +0 -1
- package/dist/broker/aggregate/aggregate.catalog.d.ts +0 -54
- package/dist/broker/aggregate/aggregate.catalog.js +0 -105
- package/dist/broker/aggregate/aggregate.catalog.js.map +0 -1
- package/dist/broker/aggregate/aggregate.server.d.ts +0 -47
- package/dist/broker/aggregate/aggregate.server.js +0 -151
- package/dist/broker/aggregate/aggregate.server.js.map +0 -1
- package/dist/broker/aggregate/provider.client.session.d.ts +0 -52
- package/dist/broker/aggregate/provider.client.session.js +0 -140
- package/dist/broker/aggregate/provider.client.session.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.info.d.ts +0 -15
- package/dist/broker/behaviors/broker.behavior.info.js +0 -41
- package/dist/broker/behaviors/broker.behavior.info.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.providers.d.ts +0 -19
- package/dist/broker/behaviors/broker.behavior.providers.js +0 -69
- package/dist/broker/behaviors/broker.behavior.providers.js.map +0 -1
- package/dist/broker/broker.context.d.ts +0 -59
- package/dist/broker/broker.context.js +0 -2
- package/dist/broker/broker.context.js.map +0 -1
- package/dist/broker/broker.grammars.d.ts +0 -130
- package/dist/broker/broker.grammars.js +0 -229
- package/dist/broker/broker.grammars.js.map +0 -1
- package/dist/broker/broker.server.d.ts +0 -66
- package/dist/broker/broker.server.js +0 -73
- package/dist/broker/broker.server.js.map +0 -1
- package/dist/broker/index.d.ts +0 -9
- package/dist/broker/index.js +0 -7
- package/dist/broker/index.js.map +0 -1
- package/dist/config.d.ts +0 -136
- package/dist/config.js +0 -61
- package/dist/config.js.map +0 -1
- package/dist/mcpb.loader.d.ts +0 -24
- package/dist/mcpb.loader.js +0 -161
- package/dist/mcpb.loader.js.map +0 -1
- package/dist/mcpb.unzip.d.ts +0 -6
- package/dist/mcpb.unzip.js +0 -95
- package/dist/mcpb.unzip.js.map +0 -1
- package/dist/remote.transports.d.ts +0 -16
- package/dist/remote.transports.js +0 -297
- package/dist/remote.transports.js.map +0 -1
- package/dist/remote.upstream.d.ts +0 -36
- package/dist/remote.upstream.js +0 -52
- package/dist/remote.upstream.js.map +0 -1
- package/dist/stdio.upstream.d.ts +0 -45
- package/dist/stdio.upstream.js +0 -85
- package/dist/stdio.upstream.js.map +0 -1
- package/dist/upstream.d.ts +0 -33
- package/dist/upstream.js +0 -2
- package/dist/upstream.js.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.js +0 -9
- package/dist/version.js.map +0 -1
- package/dist/ws.tunnel.builder.d.ts +0 -139
- package/dist/ws.tunnel.builder.js +0 -205
- package/dist/ws.tunnel.builder.js.map +0 -1
- package/dist/ws.tunnel.d.ts +0 -373
- package/dist/ws.tunnel.js +0 -1090
- package/dist/ws.tunnel.js.map +0 -1
- /package/dist/{broker/grammars → grammars}/default/en.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/fr.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/zh.json +0 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
export { WsTunnel } from
|
|
2
|
-
|
|
3
|
-
export { StdioUpstream } from "./stdio.upstream.js";
|
|
4
|
-
export { RemoteUpstream } from "./remote.upstream.js";
|
|
5
|
-
// `.mcpb` bundle loading — verifies + unpacks a bundle into a stdio upstream.
|
|
6
|
-
export { loadMcpbBundle } from "./mcpb.loader.js";
|
|
7
|
-
export { unzipMcpb } from "./mcpb.unzip.js";
|
|
8
|
-
// Broker introspection — tier 1.
|
|
9
|
-
export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
|
|
10
|
-
export { brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar } from "./broker/index.js";
|
|
11
|
-
export { VERSION, PACKAGE_NAME } from "./version.js";
|
|
12
|
-
// JSON config file used by `bin.ts` at startup. Exported so a programmatic
|
|
13
|
-
// embedder can re-use the same loader against a custom path.
|
|
14
|
-
export { loadBrokerConfig, DEFAULT_CONFIG_FILENAME } from "./config.js";
|
|
1
|
+
export { AuthError, BROKER_PROVIDER_NAME, BrokerInfoBehavior, BrokerProvidersBehavior, ConfigPolicyEngine, ConfiguredCapabilityClassifier, DEFAULT_CONFIG_FILENAME, DefaultSlotResourceResolver, HttpAuthGuard, JwtSubjectMapper, JwtTokenValidator, PACKAGE_NAME, RemoteUpstream, ResourcePath, ResourcePathPattern, SharedSecretProviderAuthenticator, StdioUpstream, SubjectMappingError, VERSION, WsTunnel, WsTunnelBuilder, authorizationWithEngine, brokerGrammarKey, buildJwtAuth, buildResourceMetadata, compileAuthorizationPolicy, hasAuthorizationPolicies, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerConfig, loadBrokerGrammar, loadMcpbBundle, normalizeProviderAuthentication, providerMayPublish, scopesOf, startBrokerServer, unzipMcpb, validateCapability } from './chunk-FTDKH2C4.js';
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
15
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanmycelium/mcp-broker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "WebSocket-based Model Context Protocol broker. Aggregates multiple MCP providers behind a single endpoint with stdio, SSE, and Streamable HTTP client transports.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/pandaGaume/mcp-broker.git",
|
|
11
|
-
"directory": "node"
|
|
11
|
+
"directory": "node/packages/broker"
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://github.com/pandaGaume/mcp-broker#readme",
|
|
14
14
|
"bugs": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"dist",
|
|
37
37
|
"src",
|
|
38
38
|
"scripts",
|
|
39
|
+
"web",
|
|
39
40
|
".mcp-broker.example",
|
|
40
41
|
"LICENSE",
|
|
41
42
|
"README.md"
|
|
@@ -48,15 +49,17 @@
|
|
|
48
49
|
}
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
|
-
"build": "
|
|
52
|
-
"clean": "rimraf dist
|
|
53
|
-
"compile": "tsc -b tsconfig.build.json",
|
|
52
|
+
"build": "tsup && npm run copy:assets",
|
|
53
|
+
"clean": "rimraf dist",
|
|
54
54
|
"copy:assets": "node scripts/copy-assets.mjs",
|
|
55
|
-
"watch": "
|
|
55
|
+
"watch": "tsup --watch",
|
|
56
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
56
57
|
"start": "node dist/bin.js",
|
|
57
58
|
"pack:mcpb": "npm run build && node scripts/pack-mcpb.mjs",
|
|
58
59
|
"test": "vitest run",
|
|
59
60
|
"test:watch": "vitest",
|
|
61
|
+
"demo:oauth": "npm run build && node web/demos/oauth-lab/server/start.mjs",
|
|
62
|
+
"demo:oauth:smoke": "node web/demos/oauth-lab/server/smoke-test.mjs",
|
|
60
63
|
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
61
64
|
"lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" --fix",
|
|
62
65
|
"format": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
@@ -65,11 +68,13 @@
|
|
|
65
68
|
"prepublishOnly": "npm run lint && npm run build && npm test"
|
|
66
69
|
},
|
|
67
70
|
"dependencies": {
|
|
68
|
-
"@cyanmycelium/mcp-core": "^0.
|
|
71
|
+
"@cyanmycelium/mcp-core": "^0.7.0",
|
|
72
|
+
"jose": "^6.2.3",
|
|
69
73
|
"open": "^11.0.0",
|
|
70
74
|
"ws": "^8.18.0"
|
|
71
75
|
},
|
|
72
76
|
"devDependencies": {
|
|
77
|
+
"@cyanmycelium/mcp-broker-provider": "^0.1.0",
|
|
73
78
|
"@types/node": "^20.11.0",
|
|
74
79
|
"@types/ws": "^8.5.0",
|
|
75
80
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
@@ -81,7 +86,8 @@
|
|
|
81
86
|
"rimraf": "~6.0.1",
|
|
82
87
|
"selfsigned": "^2.4.1",
|
|
83
88
|
"tslib": "^2.8.1",
|
|
89
|
+
"tsup": "^8.5.1",
|
|
84
90
|
"typescript": "^5.4.0",
|
|
85
|
-
"vitest": "^1.
|
|
91
|
+
"vitest": "^4.1.9"
|
|
86
92
|
}
|
|
87
93
|
}
|
package/scripts/copy-assets.mjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copies non-TypeScript assets from `src/` to `dist/`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* A bundler emits no `.json`, and it also **flattens the module tree**: code
|
|
5
|
+
* that lived in `src/broker/` ends up in a bundle at the root of `dist/`. Any
|
|
6
|
+
* asset resolved at runtime from `fileURLToPath(import.meta.url)` must therefore
|
|
7
|
+
* be copied next to the bundle, not to a path mirroring the source layout.
|
|
8
|
+
*
|
|
9
|
+
* That is why each entry below is an explicit `from → to` pair rather than a
|
|
10
|
+
* single relative path: the two sides genuinely differ, and assuming otherwise
|
|
11
|
+
* builds a `dist` that passes every test (they run against `src`) and fails
|
|
12
|
+
* the moment the published artifact is executed.
|
|
8
13
|
*
|
|
9
14
|
* Usage (called from npm scripts):
|
|
10
15
|
* node scripts/copy-assets.mjs
|
|
@@ -18,17 +23,18 @@ const here = dirname(fileURLToPath(import.meta.url));
|
|
|
18
23
|
const root = join(here, "..");
|
|
19
24
|
|
|
20
25
|
const assets = [
|
|
21
|
-
// Broker
|
|
22
|
-
|
|
26
|
+
// Broker grammars, read at runtime by broker.grammars.ts relative to its own
|
|
27
|
+
// module. Bundled, that module sits at the root of `dist`.
|
|
28
|
+
{ from: "broker/grammars", to: "grammars" },
|
|
23
29
|
];
|
|
24
30
|
|
|
25
|
-
for (const
|
|
26
|
-
const src = join(root, "src",
|
|
27
|
-
const dst = join(root, "dist",
|
|
31
|
+
for (const { from, to } of assets) {
|
|
32
|
+
const src = join(root, "src", from);
|
|
33
|
+
const dst = join(root, "dist", to);
|
|
28
34
|
if (!existsSync(src)) {
|
|
29
35
|
console.warn(`[copy-assets] skipping missing source: ${src}`);
|
|
30
36
|
continue;
|
|
31
37
|
}
|
|
32
38
|
cpSync(src, dst, { recursive: true });
|
|
33
|
-
console.log(`[copy-assets] copied ${
|
|
39
|
+
console.log(`[copy-assets] copied ${from} -> dist/${to}`);
|
|
34
40
|
}
|
package/scripts/gen-cert.mjs
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Generates a self-signed TLS certificate for local development.
|
|
3
3
|
*
|
|
4
4
|
* Usage (from the `node/` directory):
|
|
5
|
-
* npm run gen-cert
|
|
6
|
-
* npm run gen-cert -- --out <dir>
|
|
5
|
+
* npm run gen-cert , writes to ../certs/ (repo root)
|
|
6
|
+
* npm run gen-cert -- --out <dir> , writes to a custom directory
|
|
7
7
|
*
|
|
8
8
|
* Outputs:
|
|
9
|
-
* <outDir>/cert.pem
|
|
10
|
-
* <outDir>/key.pem
|
|
9
|
+
* <outDir>/cert.pem , TLS certificate (pass as MCP_BROKER_TLS_CERT)
|
|
10
|
+
* <outDir>/key.pem , Private key (pass as MCP_BROKER_TLS_KEY)
|
|
11
11
|
*
|
|
12
12
|
* The certificate covers: localhost, 127.0.0.1, ::1
|
|
13
13
|
* Validity: 365 days | Key: RSA 2048-bit
|
|
@@ -20,7 +20,7 @@ import { mkdirSync, writeFileSync } from "fs";
|
|
|
20
20
|
import { resolve, join } from "path";
|
|
21
21
|
import { createRequire } from "module";
|
|
22
22
|
|
|
23
|
-
// selfsigned is a CJS module
|
|
23
|
+
// selfsigned is a CJS module, use createRequire for a clean import from ESM.
|
|
24
24
|
const require = createRequire(import.meta.url);
|
|
25
25
|
const selfsigned = require("selfsigned");
|
|
26
26
|
|
package/scripts/pack-mcpb.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* ├── node_modules/ ← npm install --omit=dev (the host does not install)
|
|
13
13
|
* └── dist/ ← compiled broker
|
|
14
14
|
*
|
|
15
|
-
* Requires `dist/` to exist
|
|
15
|
+
* Requires `dist/` to exist, run `npm run build` first (the `pack:mcpb`
|
|
16
16
|
* npm script chains it).
|
|
17
17
|
*
|
|
18
18
|
* Usage (from node/):
|
|
@@ -35,13 +35,13 @@ function run(command, args, cwd) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// ── Read package metadata
|
|
38
|
+
// ── Read package metadata, single source of truth for version + deps ───────
|
|
39
39
|
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
40
40
|
const { version, dependencies } = pkg;
|
|
41
41
|
|
|
42
42
|
// ── Preconditions ───────────────────────────────────────────────────────────
|
|
43
43
|
if (!existsSync(join(root, "dist", "bin.js"))) {
|
|
44
|
-
console.error("[pack-mcpb] dist/bin.js not found
|
|
44
|
+
console.error("[pack-mcpb] dist/bin.js not found, run `npm run build` first.");
|
|
45
45
|
process.exit(1);
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -55,7 +55,7 @@ mkdirSync(stage, { recursive: true });
|
|
|
55
55
|
cpSync(join(root, "dist"), join(stage, "dist"), { recursive: true });
|
|
56
56
|
console.log("[pack-mcpb] copied dist/");
|
|
57
57
|
|
|
58
|
-
// ── Production package.json
|
|
58
|
+
// ── Production package.json, drives the bundled npm install ────────────────
|
|
59
59
|
// type=module is required so Node treats the compiled .js as ESM.
|
|
60
60
|
writeFileSync(
|
|
61
61
|
join(stage, "package.json"),
|
|
@@ -81,4 +81,4 @@ console.log("[pack-mcpb] running mcpb pack …");
|
|
|
81
81
|
run("npx", ["--yes", "@anthropic-ai/mcpb@2", "pack", stage, output]);
|
|
82
82
|
|
|
83
83
|
const sizeMb = (statSync(output).size / 1024 / 1024).toFixed(2);
|
|
84
|
-
console.log(`[pack-mcpb] done
|
|
84
|
+
console.log(`[pack-mcpb] done, ${output} (${sizeMb} MB)`);
|
package/scripts/sign-bundle.mjs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Signs `.mcpb` bundles for the broker's bundle loader
|
|
2
|
+
* Signs `.mcpb` bundles for the broker's bundle loader, built-ins only.
|
|
3
3
|
*
|
|
4
4
|
* The broker verifies a **detached signature** of a `.mcpb` file against a
|
|
5
5
|
* trusted public key (see `src/mcpb.loader.ts`). This script produces that
|
|
6
|
-
* signature using `node:crypto` only
|
|
6
|
+
* signature using `node:crypto` only: no dependency on OpenSSL or the
|
|
7
7
|
* `@anthropic-ai/mcpb` CLI.
|
|
8
8
|
*
|
|
9
9
|
* Usage (from the `node/` directory):
|
|
10
10
|
*
|
|
11
11
|
* node scripts/sign-bundle.mjs keygen [outDir]
|
|
12
12
|
* Generates an Ed25519 key pair:
|
|
13
|
-
* <outDir>/mcpb-signing.key.pem
|
|
14
|
-
* <outDir>/mcpb-signing.pub.pem
|
|
13
|
+
* <outDir>/mcpb-signing.key.pem , private key (keep secret)
|
|
14
|
+
* <outDir>/mcpb-signing.pub.pem , public key (point `publicKey` at this)
|
|
15
15
|
* outDir defaults to the current directory.
|
|
16
16
|
*
|
|
17
17
|
* node scripts/sign-bundle.mjs sign <bundle.mcpb> <privateKey.pem> [signaturePath]
|
|
18
18
|
* Writes the detached signature. signaturePath defaults to
|
|
19
|
-
* `<bundle.mcpb>.sig
|
|
19
|
+
* `<bundle.mcpb>.sig`: the path the broker looks for by default.
|
|
20
20
|
*/
|
|
21
21
|
import { generateKeyPairSync, createPrivateKey, sign } from "node:crypto";
|
|
22
22
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
@@ -57,5 +57,5 @@ if (command === "keygen") {
|
|
|
57
57
|
writeFileSync(sigPath, signature);
|
|
58
58
|
console.log(`[sign-bundle] signature (${keyType}) → ${sigPath}`);
|
|
59
59
|
} else {
|
|
60
|
-
fail('unknown command
|
|
60
|
+
fail('unknown command, use "keygen" or "sign". See the file header for usage.');
|
|
61
61
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { JwtTokenValidator } from "./jwt.validator";
|
|
2
|
+
import type { AggregateScopeFilter, IResolvedAuth } from "./auth.types";
|
|
3
|
+
import { compileAuthorizationPolicy, DefaultSlotResourceResolver, hasAuthorizationPolicies, type IAuthorizationPolicyConfig } from "../authorization/index";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* High-level options for the default JWT/JWKS resource-server setup. Mirrors the
|
|
7
|
+
* `auth` block of the broker JSON config and is turned into a fully
|
|
8
|
+
* {@link IResolvedAuth} (with a {@link JwtTokenValidator}) by {@link buildJwtAuth}.
|
|
9
|
+
*/
|
|
10
|
+
export interface IJwtAuthOptions extends IAuthorizationPolicyConfig {
|
|
11
|
+
/** Public origin the broker is reached at (e.g. `https://mcp.example.com`). */
|
|
12
|
+
publicBaseUrl: string;
|
|
13
|
+
/** Authorization server issuer URL(s) advertised in the PRM. At least one. */
|
|
14
|
+
authorizationServers: string[];
|
|
15
|
+
/** URL of the authorization server's JWKS document. */
|
|
16
|
+
jwksUri: string;
|
|
17
|
+
/** Expected token issuer(s). Defaults to the sole authorization server. */
|
|
18
|
+
issuer?: string | string[];
|
|
19
|
+
/** Scopes advertised in the PRM `scopes_supported`. */
|
|
20
|
+
scopesSupported?: string[];
|
|
21
|
+
/** Baseline scope(s) required to reach any slot. */
|
|
22
|
+
requiredScopes?: string[];
|
|
23
|
+
/** Per-slot required-scope overrides (e.g. an admin scope for `_broker`). */
|
|
24
|
+
perSlotScopes?: Record<string, string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Per-provider scope requirements for the `_all` aggregate. A caller sees a
|
|
27
|
+
* provider in `_all` only if it holds at least one of the listed scopes.
|
|
28
|
+
* Providers not listed here stay visible to every authenticated caller.
|
|
29
|
+
* Turned into an {@link AggregateScopeFilter} automatically.
|
|
30
|
+
*/
|
|
31
|
+
providerScopes?: Record<string, string[]>;
|
|
32
|
+
/** Leeway in seconds for token `exp`/`nbf` checks. */
|
|
33
|
+
clockToleranceSec?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Builds the default aggregate filter from a per-provider scope map. */
|
|
37
|
+
function makeProviderScopeFilter(providerScopes: Record<string, string[]>): AggregateScopeFilter {
|
|
38
|
+
return (principal, providerName) => {
|
|
39
|
+
const required = providerScopes[providerName];
|
|
40
|
+
if (!required || required.length === 0) return true; // unlisted ⇒ visible to all
|
|
41
|
+
return required.some((scope) => principal.scopes.has(scope));
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Removes a single trailing slash so resource URIs concatenate cleanly. */
|
|
46
|
+
function stripTrailingSlash(url: string): string {
|
|
47
|
+
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Builds an {@link IResolvedAuth} backed by a {@link JwtTokenValidator}. Validates
|
|
52
|
+
* the required inputs up front and throws a descriptive error on misconfig, so
|
|
53
|
+
* an operator sees the problem at boot rather than as opaque `401`s later.
|
|
54
|
+
*/
|
|
55
|
+
export function buildJwtAuth(options: IJwtAuthOptions): IResolvedAuth {
|
|
56
|
+
if (!options.publicBaseUrl) {
|
|
57
|
+
throw new Error("auth: publicBaseUrl is required.");
|
|
58
|
+
}
|
|
59
|
+
if (!options.authorizationServers || options.authorizationServers.length === 0) {
|
|
60
|
+
throw new Error("auth: at least one authorizationServers entry is required.");
|
|
61
|
+
}
|
|
62
|
+
if (!options.jwksUri) {
|
|
63
|
+
throw new Error("auth: jwksUri is required.");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const publicBaseUrl = stripTrailingSlash(options.publicBaseUrl);
|
|
67
|
+
const issuer = options.issuer ?? (options.authorizationServers.length === 1 ? options.authorizationServers[0] : undefined);
|
|
68
|
+
|
|
69
|
+
const validator = new JwtTokenValidator({
|
|
70
|
+
jwksUri: options.jwksUri,
|
|
71
|
+
issuer,
|
|
72
|
+
clockToleranceSec: options.clockToleranceSec,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const resolved: IResolvedAuth = {
|
|
76
|
+
publicBaseUrl,
|
|
77
|
+
authorizationServers: options.authorizationServers,
|
|
78
|
+
validator,
|
|
79
|
+
};
|
|
80
|
+
if (options.scopesSupported) resolved.scopesSupported = options.scopesSupported;
|
|
81
|
+
if (options.requiredScopes) resolved.requiredScopes = options.requiredScopes;
|
|
82
|
+
if (options.perSlotScopes) resolved.perSlotScopes = options.perSlotScopes;
|
|
83
|
+
if (options.providerScopes && Object.keys(options.providerScopes).length > 0) {
|
|
84
|
+
console.warn("[mcp-broker] auth.providerScopes is deprecated; migrate to roles and hierarchical assignments.");
|
|
85
|
+
resolved.aggregateScopeFilter = makeProviderScopeFilter(options.providerScopes);
|
|
86
|
+
}
|
|
87
|
+
if (options.slotResources && Object.keys(options.slotResources).length > 0) {
|
|
88
|
+
resolved.slotResourceResolver = new DefaultSlotResourceResolver(options.slotResources);
|
|
89
|
+
}
|
|
90
|
+
if (hasAuthorizationPolicies(options)) {
|
|
91
|
+
resolved.authorization = compileAuthorizationPolicy(options);
|
|
92
|
+
resolved.slotResourceResolver = resolved.authorization.slotResourceResolver;
|
|
93
|
+
}
|
|
94
|
+
return resolved;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @deprecated Use {@link IJwtAuthOptions}. */
|
|
98
|
+
export type JwtAuthOptions = IJwtAuthOptions;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core contracts for the broker's OAuth 2.1 **resource server** layer.
|
|
3
|
+
*
|
|
4
|
+
* The broker never acts as an authorization server: it only validates the
|
|
5
|
+
* access tokens minted by an external AS and advertises that AS through
|
|
6
|
+
* Protected Resource Metadata (RFC 9728). These types are the seam every other
|
|
7
|
+
* auth module builds on, so a host can drop in a custom {@link ITokenValidator}
|
|
8
|
+
* (e.g. RFC 7662 introspection) without touching the enforcement code.
|
|
9
|
+
*
|
|
10
|
+
* Everything the MCP specification itself defines comes from `mcp-core` and is
|
|
11
|
+
* re-exported here under the broker's historical names: the claim shape, the
|
|
12
|
+
* validator seam, the error carrying a challenge. What stays broker-owned is
|
|
13
|
+
* what the spec does not define, namely a multi-slot resource server whose
|
|
14
|
+
* principals feed a hierarchical policy engine.
|
|
15
|
+
*/
|
|
16
|
+
import { McpAuthError, scopesOf as mcpScopesOf, type IAccessTokenClaims, type IMcpPrincipal, type ITokenValidator } from "@cyanmycelium/mcp-core";
|
|
17
|
+
import type { IAuthorizationSubject, IPolicyAuthorization, ISlotResourceResolver } from "../authorization/index";
|
|
18
|
+
|
|
19
|
+
export type { IAccessTokenClaims, ITokenValidator } from "@cyanmycelium/mcp-core";
|
|
20
|
+
|
|
21
|
+
/** OAuth 2.1 error codes the broker emits in `WWW-Authenticate` challenges. */
|
|
22
|
+
export type AuthErrorCode = import("@cyanmycelium/mcp-core").McpAuthErrorCode;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A thrown authorization failure carrying the HTTP status and OAuth error code
|
|
26
|
+
* the enforcement point should surface. `scope` is set for `insufficient_scope`
|
|
27
|
+
* challenges to advertise the scope(s) the resource requires.
|
|
28
|
+
*
|
|
29
|
+
* The broker's own name for `mcp-core`'s `McpAuthError`, kept so `instanceof`
|
|
30
|
+
* checks and the published API survive the consolidation. There is one class at
|
|
31
|
+
* runtime, so an error thrown by `mcp-core` is caught by the broker and the
|
|
32
|
+
* other way round.
|
|
33
|
+
*/
|
|
34
|
+
export const AuthError = McpAuthError;
|
|
35
|
+
export type AuthError = McpAuthError;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The authenticated caller, produced once a token passes validation and the
|
|
39
|
+
* required scopes are satisfied. Threaded through the request so downstream
|
|
40
|
+
* components (e.g. the `_all` aggregate) can make scope-aware decisions.
|
|
41
|
+
*
|
|
42
|
+
* Extends `mcp-core`'s principal with the subject the policy engine reasons
|
|
43
|
+
* about, which the specification says nothing about and which therefore stays
|
|
44
|
+
* here.
|
|
45
|
+
*/
|
|
46
|
+
export interface IPrincipal extends IMcpPrincipal {
|
|
47
|
+
readonly claims: IAccessTokenClaims;
|
|
48
|
+
readonly scopes: ReadonlySet<string>;
|
|
49
|
+
/** Subjects derived exclusively from validated token claims. */
|
|
50
|
+
readonly subject?: IAuthorizationSubject;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Decides, per authenticated caller, whether a given provider is visible in the
|
|
55
|
+
* `_all` aggregate. This is the content-confidentiality enforcement point: a
|
|
56
|
+
* client only sees (and can call) tools/prompts from providers it is authorized
|
|
57
|
+
* for. Return `true` to include the provider for this principal.
|
|
58
|
+
*/
|
|
59
|
+
export type AggregateScopeFilter = (principal: IPrincipal, providerName: string) => boolean;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A fully resolved authorization configuration, ready for the enforcement
|
|
63
|
+
* layer. Built either from JSON config (via `buildJwtAuth`) or supplied
|
|
64
|
+
* directly by an embedder with a custom {@link ITokenValidator}.
|
|
65
|
+
*/
|
|
66
|
+
export interface IResolvedAuth {
|
|
67
|
+
/**
|
|
68
|
+
* Public origin the broker is reached at, used to build canonical resource
|
|
69
|
+
* URIs and metadata URLs. No trailing slash (e.g. `https://mcp.example.com`).
|
|
70
|
+
*/
|
|
71
|
+
publicBaseUrl: string;
|
|
72
|
+
/** One or more authorization server issuer URLs, advertised in the PRM. */
|
|
73
|
+
authorizationServers: string[];
|
|
74
|
+
/** Optional list of scopes advertised in the PRM `scopes_supported`. */
|
|
75
|
+
scopesSupported?: string[];
|
|
76
|
+
/** The token validator (JWKS-backed by default). */
|
|
77
|
+
validator: ITokenValidator;
|
|
78
|
+
/** Baseline scope(s) required to reach any slot. Empty ⇒ any valid token. */
|
|
79
|
+
requiredScopes?: string[];
|
|
80
|
+
/** Per-slot required-scope overrides (e.g. an admin scope for `_broker`). */
|
|
81
|
+
perSlotScopes?: Record<string, string[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Per-caller filter for the `_all` aggregate. When set, a client's view of
|
|
84
|
+
* `_all` is narrowed to the providers this returns `true` for. When absent,
|
|
85
|
+
* every authenticated caller sees the full aggregate.
|
|
86
|
+
*/
|
|
87
|
+
aggregateScopeFilter?: AggregateScopeFilter;
|
|
88
|
+
/** Compiled hierarchical policy runtime, absent for legacy OAuth behavior. */
|
|
89
|
+
authorization?: IPolicyAuthorization;
|
|
90
|
+
/** Optional resolver usable for provider namespace checks without policies. */
|
|
91
|
+
slotResourceResolver?: ISlotResourceResolver;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extracts the effective set of granted scopes from token claims.
|
|
96
|
+
*
|
|
97
|
+
* A deliberate superset of `mcp-core`'s: OAuth 2.1 only defines the
|
|
98
|
+
* space-delimited `scope` string, which is what the spec-level helper reads,
|
|
99
|
+
* but several authorization servers emit an array-form `scopes` claim instead.
|
|
100
|
+
* Dropping that here would silently strip every scope for those deployments, so
|
|
101
|
+
* the two are unioned. The `scope` half is parsed by `mcp-core` rather than
|
|
102
|
+
* re-implemented.
|
|
103
|
+
*/
|
|
104
|
+
export function scopesOf(claims: IAccessTokenClaims): Set<string> {
|
|
105
|
+
const set = new Set<string>(mcpScopesOf(claims));
|
|
106
|
+
const arrayForm: unknown = claims["scopes"];
|
|
107
|
+
if (Array.isArray(arrayForm)) {
|
|
108
|
+
for (const scope of arrayForm) if (typeof scope === "string" && scope) set.add(scope);
|
|
109
|
+
}
|
|
110
|
+
return set;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** @deprecated Use {@link IAccessTokenClaims}. */
|
|
114
|
+
export type AccessTokenClaims = IAccessTokenClaims;
|
|
115
|
+
/** @deprecated Use {@link ITokenValidator}. */
|
|
116
|
+
export type TokenValidator = ITokenValidator;
|
|
117
|
+
/** @deprecated Use {@link IPrincipal}. */
|
|
118
|
+
export type Principal = IPrincipal;
|
|
119
|
+
/** @deprecated Use {@link IResolvedAuth}. */
|
|
120
|
+
export type ResolvedAuth = IResolvedAuth;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
|
+
import { bearerToken, buildChallengeHeader, PROTECTED_RESOURCE_METADATA_PREFIX } from "@cyanmycelium/mcp-core";
|
|
3
|
+
import { AuthError, scopesOf, type IPrincipal, type IResolvedAuth } from "./auth.types";
|
|
4
|
+
import { buildResourceMetadata, type IProtectedResourceMetadata } from "./resource.metadata";
|
|
5
|
+
import { SubjectMappingError } from "../authorization/index";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Well-known prefix under which per-slot Protected Resource Metadata is served.
|
|
9
|
+
*
|
|
10
|
+
* Carries a trailing slash because every use here splits a slot off it, while
|
|
11
|
+
* `mcp-core` exports the bare RFC 9728 prefix.
|
|
12
|
+
*/
|
|
13
|
+
const PRM_PREFIX = `${PROTECTED_RESOURCE_METADATA_PREFIX}/`;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The HTTP enforcement point for the resource-server layer. Wraps a
|
|
17
|
+
* {@link IResolvedAuth} plus the configured `/mcp` path suffix and turns it into
|
|
18
|
+
* the three operations the transport needs: serve Protected Resource Metadata,
|
|
19
|
+
* authorize a request, and write an RFC 9728 `401`/`403` challenge.
|
|
20
|
+
*
|
|
21
|
+
* A slot's **canonical resource URI** is `<publicBaseUrl>/<slot>/<mcp>` and is
|
|
22
|
+
* used uniformly across all of that slot's HTTP endpoints (`/mcp`, `/sse`,
|
|
23
|
+
* `/messages`) so a single token audience covers the whole slot.
|
|
24
|
+
*/
|
|
25
|
+
export class HttpAuthGuard {
|
|
26
|
+
private readonly _auth: IResolvedAuth;
|
|
27
|
+
/** The `/mcp` suffix without a leading slash, e.g. `"mcp"`. */
|
|
28
|
+
private readonly _mcpSuffix: string;
|
|
29
|
+
|
|
30
|
+
constructor(auth: IResolvedAuth, mcpSuffix: string) {
|
|
31
|
+
this._auth = auth;
|
|
32
|
+
this._mcpSuffix = mcpSuffix.replace(/^\//, "");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Canonical resource identifier for a slot (RFC 8707 §2). */
|
|
36
|
+
resourceFor(slot: string): string {
|
|
37
|
+
return `${this._auth.publicBaseUrl}/${encodeURIComponent(slot)}/${this._mcpSuffix}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** RFC 9728 metadata URL for a slot, advertised in the `401` challenge. */
|
|
41
|
+
metadataUrlFor(slot: string): string {
|
|
42
|
+
return `${this._auth.publicBaseUrl}${PRM_PREFIX}${encodeURIComponent(slot)}/${this._mcpSuffix}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Required scope(s) for a slot: per-slot override, else the baseline. */
|
|
46
|
+
requiredScopesFor(slot: string): string[] {
|
|
47
|
+
return this._auth.perSlotScopes?.[slot] ?? this._auth.requiredScopes ?? [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The RFC 9728 metadata document for a slot. */
|
|
51
|
+
metadataFor(slot: string): IProtectedResourceMetadata {
|
|
52
|
+
return buildResourceMetadata({
|
|
53
|
+
resource: this.resourceFor(slot),
|
|
54
|
+
authorizationServers: this._auth.authorizationServers,
|
|
55
|
+
scopesSupported: this._auth.scopesSupported,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* If `rawUrl` is a Protected Resource Metadata request
|
|
61
|
+
* (`/.well-known/oauth-protected-resource/<slot>/<mcp>`), returns the slot;
|
|
62
|
+
* otherwise `null`.
|
|
63
|
+
*/
|
|
64
|
+
matchMetadataRequest(rawUrl: string): string | null {
|
|
65
|
+
if (!rawUrl.startsWith(PRM_PREFIX)) return null;
|
|
66
|
+
const parts = rawUrl.slice(PRM_PREFIX.length).split("/").filter(Boolean);
|
|
67
|
+
if (parts.length !== 2 || parts[1] !== this._mcpSuffix) return null;
|
|
68
|
+
return decodeURIComponent(parts[0]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validates the request's bearer token against the slot's canonical resource
|
|
73
|
+
* and enforces the slot's required scopes. Resolves to the {@link IPrincipal}
|
|
74
|
+
* on success; rejects with an {@link AuthError} (`401` missing/invalid token,
|
|
75
|
+
* `403` insufficient scope) otherwise.
|
|
76
|
+
*/
|
|
77
|
+
async authorize(req: IncomingMessage, slot: string): Promise<IPrincipal> {
|
|
78
|
+
const token = bearerToken(req.headers["authorization"]);
|
|
79
|
+
if (!token) {
|
|
80
|
+
throw new AuthError(401, "invalid_token", "Missing bearer token");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const claims = await this._auth.validator.validate(token, this.resourceFor(slot));
|
|
84
|
+
const scopes = scopesOf(claims);
|
|
85
|
+
|
|
86
|
+
const required = this.requiredScopesFor(slot);
|
|
87
|
+
const missing = required.filter((s) => !scopes.has(s));
|
|
88
|
+
if (missing.length > 0) {
|
|
89
|
+
throw new AuthError(403, "insufficient_scope", `Missing required scope(s): ${missing.join(" ")}`, required.join(" "));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let subject: IPrincipal["subject"];
|
|
93
|
+
try {
|
|
94
|
+
subject = this._auth.authorization?.subjectMapper.map(claims);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof SubjectMappingError) {
|
|
97
|
+
throw new AuthError(403, "insufficient_scope", "Malformed configured JWT subject claim");
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return subject ? { claims, scopes, subject } : { claims, scopes };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Builds the RFC 9728 §5.1 `WWW-Authenticate` header value for a challenge.
|
|
107
|
+
* Always points the client at the slot's metadata URL so it can discover the
|
|
108
|
+
* authorization server and retry. Shared by the HTTP and WebSocket paths.
|
|
109
|
+
*/
|
|
110
|
+
challengeHeader(slot: string, err: AuthError): string {
|
|
111
|
+
return buildChallengeHeader({
|
|
112
|
+
resourceMetadata: this.metadataUrlFor(slot),
|
|
113
|
+
error: err.code,
|
|
114
|
+
errorDescription: err.description,
|
|
115
|
+
scope: err.scope,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Writes an RFC 9728 §5.1 `WWW-Authenticate` challenge and the matching
|
|
121
|
+
* status to an HTTP response.
|
|
122
|
+
*/
|
|
123
|
+
writeChallenge(res: ServerResponse, slot: string, err: AuthError): void {
|
|
124
|
+
res.setHeader("WWW-Authenticate", this.challengeHeader(slot, err));
|
|
125
|
+
res.writeHead(err.status, { "Content-Type": "application/json; charset=utf-8" });
|
|
126
|
+
res.end(JSON.stringify({ error: err.code, error_description: err.description }));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the broker's OAuth 2.1 resource-server layer. See the individual
|
|
3
|
+
* modules for details; the transport wires these up in `ws.tunnel.ts`.
|
|
4
|
+
*/
|
|
5
|
+
export { AuthError, scopesOf } from "./auth.types";
|
|
6
|
+
export type {
|
|
7
|
+
IAccessTokenClaims,
|
|
8
|
+
ITokenValidator,
|
|
9
|
+
AuthErrorCode,
|
|
10
|
+
IPrincipal,
|
|
11
|
+
IResolvedAuth,
|
|
12
|
+
AggregateScopeFilter,
|
|
13
|
+
AccessTokenClaims,
|
|
14
|
+
TokenValidator,
|
|
15
|
+
Principal,
|
|
16
|
+
ResolvedAuth,
|
|
17
|
+
} from "./auth.types";
|
|
18
|
+
export { JwtTokenValidator } from "./jwt.validator";
|
|
19
|
+
export type { IJwtValidatorOptions, JwtValidatorOptions } from "./jwt.validator";
|
|
20
|
+
export { buildResourceMetadata } from "./resource.metadata";
|
|
21
|
+
export type { IProtectedResourceMetadata, ProtectedResourceMetadata } from "./resource.metadata";
|
|
22
|
+
export { HttpAuthGuard } from "./http.auth";
|
|
23
|
+
export { buildJwtAuth } from "./auth.config";
|
|
24
|
+
export type { IJwtAuthOptions, JwtAuthOptions } from "./auth.config";
|
|
25
|
+
export { SharedSecretProviderAuthenticator } from "./provider.auth";
|
|
26
|
+
export { normalizeProviderAuthentication, providerMayPublish } from "./provider.auth";
|
|
27
|
+
export type {
|
|
28
|
+
IProviderAuthenticator,
|
|
29
|
+
IProviderPrincipal,
|
|
30
|
+
ProviderAuthenticationResult,
|
|
31
|
+
ProviderAuthenticator,
|
|
32
|
+
ProviderAuthenticatorReturn,
|
|
33
|
+
ProviderPrincipal,
|
|
34
|
+
} from "./provider.auth";
|