stitchkit 0.23.0 → 0.24.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/dist/tools/oauth-provider.d.ts +10 -0
- package/dist/tools/oauth-provider.d.ts.map +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +21 -10
- package/llms-full.txt +29 -6
- package/package.json +1 -1
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import type { RawRoute } from '../server/types';
|
|
2
|
+
/**
|
|
3
|
+
* OpenID Connect DCR `application_type` (SEP-837). A `native` client (desktop /
|
|
4
|
+
* CLI) may register an `http` loopback redirect; a `web` client may not — the
|
|
5
|
+
* mismatch is the usual cause of a `redirect_uri` rejection for CLI clients.
|
|
6
|
+
*/
|
|
7
|
+
export type ApplicationType = 'native' | 'web';
|
|
2
8
|
/** A client as registered via DCR. Public clients (PKCE) carry no secret. */
|
|
3
9
|
export interface RegisteredClient {
|
|
4
10
|
clientId: string;
|
|
5
11
|
redirectUris: string[];
|
|
6
12
|
clientName?: string;
|
|
13
|
+
/** The `application_type` the client declared, when it declared one. */
|
|
14
|
+
applicationType?: ApplicationType;
|
|
7
15
|
}
|
|
8
16
|
/** Metadata posted to `/register` (RFC 7591) before a client id is assigned. */
|
|
9
17
|
export interface ClientMetadata {
|
|
10
18
|
redirectUris: string[];
|
|
11
19
|
clientName?: string;
|
|
12
20
|
tokenEndpointAuthMethod?: string;
|
|
21
|
+
/** `native` (desktop / CLI, loopback allowed) or `web` (https only). */
|
|
22
|
+
applicationType?: ApplicationType;
|
|
13
23
|
}
|
|
14
24
|
/** State persisted between `/authorize` and `/token`, keyed by the auth code. */
|
|
15
25
|
export interface AuthCodeData {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../../src/tools/oauth-provider.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../../src/tools/oauth-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export { type DownloadToolConfig, mountDownload } from './tools/mount-download';
|
|
|
17
17
|
export { mountUpload, type UploadToolConfig } from './tools/mount-upload';
|
|
18
18
|
export { mountWait, type WaitToolConfig } from './tools/mount-wait';
|
|
19
19
|
export { oauthProtectedResourceRoute, PROTECTED_RESOURCE_PATH, type ProtectedResourceConfig, protectedResourceMetadataUrl, wwwAuthenticateHeader, } from './tools/oauth-metadata';
|
|
20
|
-
export { type AuthCodeData, type AuthRequest, type ClientMetadata, mountOAuthProvider, type OAuthProviderConfig, type RefreshData, type RegisteredClient, } from './tools/oauth-provider';
|
|
20
|
+
export { type ApplicationType, type AuthCodeData, type AuthRequest, type ClientMetadata, mountOAuthProvider, type OAuthProviderConfig, type RefreshData, type RegisteredClient, } from './tools/oauth-provider';
|
|
21
21
|
export { type ImplementRemoteOptions, implementRemote } from './tools/remote';
|
|
22
22
|
export { createToolLogger, type ToolCallRecord, type ToolLoggerConfig, } from './tools/tool-logger';
|
|
23
23
|
export { createToolkit, type Toolkit } from './tools/toolkit';
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EACL,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,kBAAkB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EACL,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EACL,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/tools.js
CHANGED
|
@@ -615,13 +615,15 @@ function json(body, status = 200, extraHeaders) {
|
|
|
615
615
|
function oauthError(error, description, status = 400) {
|
|
616
616
|
return json({ error, error_description: description }, status);
|
|
617
617
|
}
|
|
618
|
-
function
|
|
618
|
+
function isRegistrableRedirectUri(value, applicationType) {
|
|
619
619
|
try {
|
|
620
620
|
const url = new URL(value);
|
|
621
621
|
if (url.protocol === "https:")
|
|
622
622
|
return true;
|
|
623
623
|
if (url.protocol !== "http:")
|
|
624
624
|
return false;
|
|
625
|
+
if (applicationType === "web")
|
|
626
|
+
return false;
|
|
625
627
|
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
626
628
|
return host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
627
629
|
} catch {
|
|
@@ -655,6 +657,7 @@ function mountOAuthProvider(config) {
|
|
|
655
657
|
const registerPath = `${base}/register`;
|
|
656
658
|
const authorizePath = `${base}/authorize`;
|
|
657
659
|
const tokenPath = `${base}/token`;
|
|
660
|
+
const redirectToClient = (uri, params) => redirectWith(uri, { ...params, iss: config.issuer });
|
|
658
661
|
const metadataRoute = {
|
|
659
662
|
method: "ALL",
|
|
660
663
|
path: AS_METADATA_PATH,
|
|
@@ -670,6 +673,7 @@ function mountOAuthProvider(config) {
|
|
|
670
673
|
grant_types_supported: config.refreshTokens ? ["authorization_code", "refresh_token"] : ["authorization_code"],
|
|
671
674
|
code_challenge_methods_supported: ["S256"],
|
|
672
675
|
token_endpoint_auth_methods_supported: ["none"],
|
|
676
|
+
authorization_response_iss_parameter_supported: true,
|
|
673
677
|
...config.scopesSupported && { scopes_supported: config.scopesSupported }
|
|
674
678
|
});
|
|
675
679
|
}
|
|
@@ -686,14 +690,20 @@ function mountOAuthProvider(config) {
|
|
|
686
690
|
if (!isRecord(meta)) {
|
|
687
691
|
return oauthError("invalid_client_metadata", "Body must be a JSON object");
|
|
688
692
|
}
|
|
693
|
+
const rawAppType = meta.application_type;
|
|
694
|
+
if (rawAppType !== undefined && rawAppType !== "native" && rawAppType !== "web") {
|
|
695
|
+
return oauthError("invalid_client_metadata", "application_type must be 'native' or 'web'");
|
|
696
|
+
}
|
|
697
|
+
const applicationType = rawAppType;
|
|
689
698
|
const redirectUris = meta.redirect_uris;
|
|
690
|
-
if (!Array.isArray(redirectUris) || redirectUris.length === 0 || !redirectUris.every((u) => typeof u === "string" &&
|
|
691
|
-
return oauthError("invalid_redirect_uri", "redirect_uris must be a non-empty array of absolute https URLs (http is allowed only on a loopback host)");
|
|
699
|
+
if (!Array.isArray(redirectUris) || redirectUris.length === 0 || !redirectUris.every((u) => typeof u === "string" && isRegistrableRedirectUri(u, applicationType))) {
|
|
700
|
+
return oauthError("invalid_redirect_uri", applicationType === "web" ? "redirect_uris must be a non-empty array of absolute https URLs (a web client cannot register an http loopback URI)" : "redirect_uris must be a non-empty array of absolute https URLs (http is allowed only on a loopback host)");
|
|
692
701
|
}
|
|
693
702
|
const client = await config.clients.register({
|
|
694
703
|
redirectUris,
|
|
695
704
|
clientName: typeof meta.client_name === "string" ? meta.client_name : undefined,
|
|
696
|
-
tokenEndpointAuthMethod: typeof meta.token_endpoint_auth_method === "string" ? meta.token_endpoint_auth_method : undefined
|
|
705
|
+
tokenEndpointAuthMethod: typeof meta.token_endpoint_auth_method === "string" ? meta.token_endpoint_auth_method : undefined,
|
|
706
|
+
...applicationType && { applicationType }
|
|
697
707
|
});
|
|
698
708
|
return json({
|
|
699
709
|
client_id: client.clientId,
|
|
@@ -701,7 +711,8 @@ function mountOAuthProvider(config) {
|
|
|
701
711
|
token_endpoint_auth_method: "none",
|
|
702
712
|
grant_types: config.refreshTokens ? ["authorization_code", "refresh_token"] : ["authorization_code"],
|
|
703
713
|
response_types: ["code"],
|
|
704
|
-
...client.clientName && { client_name: client.clientName }
|
|
714
|
+
...client.clientName && { client_name: client.clientName },
|
|
715
|
+
...client.applicationType && { application_type: client.applicationType }
|
|
705
716
|
}, 201);
|
|
706
717
|
}
|
|
707
718
|
};
|
|
@@ -731,27 +742,27 @@ function mountOAuthProvider(config) {
|
|
|
731
742
|
return oauthError("invalid_request", "redirect_uri does not match a registered URI");
|
|
732
743
|
}
|
|
733
744
|
if (responseType !== "code") {
|
|
734
|
-
return
|
|
745
|
+
return redirectToClient(redirectUri, {
|
|
735
746
|
error: "unsupported_response_type",
|
|
736
747
|
...state && { state }
|
|
737
748
|
});
|
|
738
749
|
}
|
|
739
750
|
if (!codeChallenge || codeChallengeMethod !== "S256") {
|
|
740
|
-
return
|
|
751
|
+
return redirectToClient(redirectUri, {
|
|
741
752
|
error: "invalid_request",
|
|
742
753
|
error_description: "PKCE S256 code_challenge is required",
|
|
743
754
|
...state && { state }
|
|
744
755
|
});
|
|
745
756
|
}
|
|
746
757
|
if (!resource) {
|
|
747
|
-
return
|
|
758
|
+
return redirectToClient(redirectUri, {
|
|
748
759
|
error: "invalid_target",
|
|
749
760
|
error_description: "resource parameter is required",
|
|
750
761
|
...state && { state }
|
|
751
762
|
});
|
|
752
763
|
}
|
|
753
764
|
if (resource !== config.resource) {
|
|
754
|
-
return
|
|
765
|
+
return redirectToClient(redirectUri, {
|
|
755
766
|
error: "invalid_target",
|
|
756
767
|
error_description: "resource is not served by this authorization server",
|
|
757
768
|
...state && { state }
|
|
@@ -772,7 +783,7 @@ function mountOAuthProvider(config) {
|
|
|
772
783
|
userId: result.userId,
|
|
773
784
|
expiresAt: Date.now() + AUTH_CODE_TTL_MS
|
|
774
785
|
});
|
|
775
|
-
return
|
|
786
|
+
return redirectToClient(redirectUri, { code, ...state && { state } });
|
|
776
787
|
}
|
|
777
788
|
};
|
|
778
789
|
const issueAccessToken = (userId, audience, clientId, scope) => signJwt({ scope, client_id: clientId }, config.signingSecret, {
|
package/llms-full.txt
CHANGED
|
@@ -1393,14 +1393,36 @@ createServer({
|
|
|
1393
1393
|
})
|
|
1394
1394
|
```
|
|
1395
1395
|
|
|
1396
|
-
Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource
|
|
1397
|
-
validate
|
|
1398
|
-
`
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
server can co-locate or live
|
|
1396
|
+
Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource and
|
|
1397
|
+
whose `iss` is the issuer — validate both in `auth` with
|
|
1398
|
+
`verifyJwt(token, secret, { audience: resource, issuer })`. `authorizeUser` is
|
|
1399
|
+
where the app authenticates the user (reuse an existing session) and records
|
|
1400
|
+
consent; return `{ userId }` to issue a code, or a `Response` to redirect the
|
|
1401
|
+
browser to a login page first. The AS and resource server can co-locate or live
|
|
1402
|
+
on separate origins. See
|
|
1402
1403
|
[ADR 0015](../decisions/0015-oauth-resource-server.md).
|
|
1403
1404
|
|
|
1405
|
+
### Authorization hardening (MCP 2026-07-28)
|
|
1406
|
+
|
|
1407
|
+
- **`iss` on every authorization response (RFC 9207, SEP-2468).** Success *and*
|
|
1408
|
+
error redirects carry `iss`, and the AS metadata advertises
|
|
1409
|
+
`authorization_response_iss_parameter_supported: true`. A client that talks to
|
|
1410
|
+
several authorization servers validates `iss` before redeeming the code, which
|
|
1411
|
+
closes the **mix-up attack** — an attacker's server cannot pass its response
|
|
1412
|
+
off as this issuer's. Additive on the wire: a client that ignores `iss` is
|
|
1413
|
+
unaffected.
|
|
1414
|
+
- **`application_type` on registration (SEP-837).** A client may declare
|
|
1415
|
+
`"native"` (desktop / CLI) or `"web"` in its DCR body. A **native** client may
|
|
1416
|
+
register an `http` loopback redirect (`http://127.0.0.1:…`, RFC 8252 §7.3); a
|
|
1417
|
+
**web** client is held to `https` only — that mismatch is the usual cause of
|
|
1418
|
+
the `redirect_uri` rejection CLI clients hit. Omit the field and registration
|
|
1419
|
+
behaves exactly as before (loopback allowed); an unknown value is rejected
|
|
1420
|
+
rather than silently defaulted.
|
|
1421
|
+
|
|
1422
|
+
> Dynamic Client Registration is **deprecated** in the 2026-07-28 spec in favour
|
|
1423
|
+
> of Client ID Metadata Documents (CIMD), with a ≥12-month window. DCR keeps
|
|
1424
|
+
> working and stays supported here; CIMD support is tracked separately.
|
|
1425
|
+
|
|
1404
1426
|
## Proxying a remote API — `implementRemote`
|
|
1405
1427
|
|
|
1406
1428
|
`implement` binds a contract to local handlers. `implementRemote` binds it to a
|
|
@@ -3470,6 +3492,7 @@ A native remote-connector auth surface for MCP — [guide](../guide/mcp-and-agen
|
|
|
3470
3492
|
| `PROTECTED_RESOURCE_PATH` | const | the well-known metadata path |
|
|
3471
3493
|
| `OAuthProviderConfig` | _type_ | config for `mountOAuthProvider` |
|
|
3472
3494
|
| `ProtectedResourceConfig` | _type_ | config for `oauthProtectedResourceRoute` |
|
|
3495
|
+
| `ApplicationType` | _type_ | DCR `application_type` — `'native'` (loopback allowed) \| `'web'` (https only) |
|
|
3473
3496
|
| `AuthCodeData` | _type_ | a stored authorization-code record |
|
|
3474
3497
|
| `AuthRequest` | _type_ | a parsed authorization request |
|
|
3475
3498
|
| `ClientMetadata` | _type_ | dynamic-client-registration metadata |
|
package/package.json
CHANGED