@zackbart/connecta 0.26.2 → 0.26.3
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/CHANGELOG.md +14 -0
- package/dist/auth/downstream-oauth.js +9 -1
- package/dist/connectors/remote-mcp.d.ts +4 -0
- package/dist/connectors/remote-mcp.js +19 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/auth.md +23 -0
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this package are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.26.3 — 2026-09-28
|
|
8
|
+
|
|
9
|
+
This patch lets downstream OAuth connections use a public client metadata
|
|
10
|
+
URL when a server supports URL-based client IDs but restricts dynamic
|
|
11
|
+
registration. Existing OAuth configurations keep their current behavior.
|
|
12
|
+
The Node template now pins 0.26.3.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `remoteMcp` OAuth auth accepts `clientMetadataUrl` and default `scope`.
|
|
17
|
+
The SDK negotiates URL-based client IDs, falling back to dynamic registration
|
|
18
|
+
when unsupported. Existing PKCE, issuer binding, encrypted storage, refresh,
|
|
19
|
+
and disconnect remain in use. Invalid settings fail at construction.
|
|
20
|
+
|
|
7
21
|
## 0.26.2 — 2026-09-27
|
|
8
22
|
|
|
9
23
|
This patch restores named client tokens as an optional auth module. Deployments
|
|
@@ -850,6 +850,8 @@ export class KvOAuthProvider {
|
|
|
850
850
|
signal;
|
|
851
851
|
clientBinding;
|
|
852
852
|
onReset;
|
|
853
|
+
scope;
|
|
854
|
+
clientMetadataUrl;
|
|
853
855
|
/**
|
|
854
856
|
* The reset generation this provider's flow started under. Every OAuth value
|
|
855
857
|
* it writes carries this epoch, so a late write can land after a reset without
|
|
@@ -869,7 +871,9 @@ export class KvOAuthProvider {
|
|
|
869
871
|
/** Stable connector configuration bound to dynamically registered clients. */
|
|
870
872
|
clientBinding,
|
|
871
873
|
/** Request-local observer so the operator route drains every reset it began. */
|
|
872
|
-
onReset
|
|
874
|
+
onReset,
|
|
875
|
+
/** SDK uses this only when the authorization server advertises support. */
|
|
876
|
+
clientMetadataUrl, scope) {
|
|
873
877
|
this.connectorId = connectorId;
|
|
874
878
|
this.storage = storage;
|
|
875
879
|
this.redirectUri = redirectUri;
|
|
@@ -879,6 +883,9 @@ export class KvOAuthProvider {
|
|
|
879
883
|
this.signal = signal;
|
|
880
884
|
this.clientBinding = clientBinding;
|
|
881
885
|
this.onReset = onReset;
|
|
886
|
+
this.scope = scope;
|
|
887
|
+
if (clientMetadataUrl !== undefined)
|
|
888
|
+
this.clientMetadataUrl = clientMetadataUrl;
|
|
882
889
|
}
|
|
883
890
|
/**
|
|
884
891
|
* Stamp the force-reauth generation the current connect flow started under.
|
|
@@ -1339,6 +1346,7 @@ export class KvOAuthProvider {
|
|
|
1339
1346
|
grant_types: ["authorization_code", "refresh_token"],
|
|
1340
1347
|
response_types: ["code"],
|
|
1341
1348
|
token_endpoint_auth_method: "none",
|
|
1349
|
+
...(this.scope !== undefined ? { scope: this.scope } : {}),
|
|
1342
1350
|
};
|
|
1343
1351
|
}
|
|
1344
1352
|
async clientInformation(ctx) {
|
|
@@ -38,6 +38,10 @@ export type RemoteMcpAuth = {
|
|
|
38
38
|
headers: Record<string, string>;
|
|
39
39
|
} | RemoteMcpCredentialAuth | {
|
|
40
40
|
type: "oauth";
|
|
41
|
+
/** Public HTTPS client metadata document, for servers supporting URL-based client IDs. */
|
|
42
|
+
clientMetadataUrl?: string;
|
|
43
|
+
/** Space-separated default scopes when the resource server does not advertise them. */
|
|
44
|
+
scope?: string;
|
|
41
45
|
};
|
|
42
46
|
/**
|
|
43
47
|
* Apply a maintained provider's slot copy and header framing to credential
|
|
@@ -396,6 +396,22 @@ function learnedUrlSafeFetch(connectorId, configured, baseFetch) {
|
|
|
396
396
|
* server or hide other connectors).
|
|
397
397
|
*/
|
|
398
398
|
export function remoteMcp(id, opts) {
|
|
399
|
+
const clientMetadataUrl = opts.auth?.type === "oauth" ? opts.auth.clientMetadataUrl : undefined;
|
|
400
|
+
const oauthScope = opts.auth?.type === "oauth" ? opts.auth.scope : undefined;
|
|
401
|
+
if (oauthScope !== undefined && !/^[\x21\x23-\x5B\x5D-\x7E]+(?: [\x21\x23-\x5B\x5D-\x7E]+)*$/.test(oauthScope)) {
|
|
402
|
+
throw new Error(`[connecta] connector "${id}" OAuth scope must contain space-separated scope tokens.`);
|
|
403
|
+
}
|
|
404
|
+
if (clientMetadataUrl !== undefined) {
|
|
405
|
+
let valid = false;
|
|
406
|
+
try {
|
|
407
|
+
const url = new URL(clientMetadataUrl);
|
|
408
|
+
valid = url.protocol === "https:" && url.pathname !== "/" &&
|
|
409
|
+
!url.username && !url.password && !url.hash;
|
|
410
|
+
}
|
|
411
|
+
catch { /* Invalid configuration is rejected below without echoing its value. */ }
|
|
412
|
+
if (!valid)
|
|
413
|
+
throw new Error(`[connecta] connector "${id}" clientMetadataUrl must be an HTTPS URL with a non-root path, without credentials or a fragment.`);
|
|
414
|
+
}
|
|
399
415
|
if (opts.authScope === "personal" && opts.auth?.type === "headers") {
|
|
400
416
|
throw new Error(`[connecta] connector "${id}" cannot combine authScope "personal" ` +
|
|
401
417
|
"with static headers. Use credential or OAuth auth so each principal " +
|
|
@@ -597,11 +613,13 @@ export function remoteMcp(id, opts) {
|
|
|
597
613
|
grant_types: ["authorization_code", "refresh_token"],
|
|
598
614
|
response_types: ["code"],
|
|
599
615
|
token_endpoint_auth_method: "none",
|
|
616
|
+
...(oauthScope !== undefined ? { scope: oauthScope } : {}),
|
|
600
617
|
},
|
|
601
618
|
authScope: opts.authScope ?? "shared",
|
|
602
619
|
versionNegotiation: opts.versionNegotiation ?? "auto",
|
|
603
620
|
redirects: opts.redirects ?? "none",
|
|
604
|
-
|
|
621
|
+
clientMetadataUrl,
|
|
622
|
+
}), (reset) => trackOAuthStartReset(ctx.requestScope ?? ctx, reset), clientMetadataUrl, oauthScope);
|
|
605
623
|
if (state)
|
|
606
624
|
state.provider = provider;
|
|
607
625
|
return provider;
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/documentation/auth.md
CHANGED
|
@@ -615,3 +615,26 @@ present, must match that owner and may then manage the connector, while an
|
|
|
615
615
|
interactive provider's explicit 403 still refuses the flow. See
|
|
616
616
|
[meta-tools](./meta-tools.md#authorization-recovery) for the recovery shapes a
|
|
617
617
|
caller actually receives.
|
|
618
|
+
|
|
619
|
+
## URL-based downstream OAuth clients
|
|
620
|
+
|
|
621
|
+
`remoteMcp` accepts `auth: { type: "oauth", clientMetadataUrl, scope }`.
|
|
622
|
+
`clientMetadataUrl` names a public HTTPS OAuth client metadata document with a
|
|
623
|
+
non-root path. It must not contain credentials or a fragment. The document
|
|
624
|
+
must include its own URL as `client_id`, the deployment's exact
|
|
625
|
+
`/oauth/callback/<connector-id>` in `redirect_uris`, authorization-code and
|
|
626
|
+
refresh-token grants, and `token_endpoint_auth_method: "none"`. Hosting that
|
|
627
|
+
public document belongs to the deployment; Connecta does not expose a public
|
|
628
|
+
route through inbound authentication.
|
|
629
|
+
|
|
630
|
+
The SDK uses the URL as the client ID only when the authorization server
|
|
631
|
+
advertises `client_id_metadata_document_supported`. Otherwise it keeps the
|
|
632
|
+
existing dynamic registration flow. State validation, PKCE, issuer binding,
|
|
633
|
+
encrypted token storage, refresh, and disconnect follow the same code paths.
|
|
634
|
+
The metadata URL and scopes participate in the saved-client configuration
|
|
635
|
+
binding, so restarting after either changes cannot reuse an old registration.
|
|
636
|
+
|
|
637
|
+
`scope` supplies space-separated default OAuth scopes through client metadata.
|
|
638
|
+
A downstream challenge or protected-resource scope declaration takes precedence,
|
|
639
|
+
and the SDK adds `offline_access` when advertised for refresh-token grants.
|
|
640
|
+
Omitting both settings preserves the existing discovery and registration flow.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of eight meta-tools.",
|