@ai-sdk/mcp 0.0.42 → 0.0.43
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 +15 -0
- package/dist/index.d.mts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +360 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +360 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -269,15 +269,6 @@ import pkceChallenge from "pkce-challenge";
|
|
|
269
269
|
|
|
270
270
|
// src/tool/oauth-types.ts
|
|
271
271
|
import { z as z3 } from "zod/v4";
|
|
272
|
-
var OAuthTokensSchema = z3.object({
|
|
273
|
-
access_token: z3.string(),
|
|
274
|
-
id_token: z3.string().optional(),
|
|
275
|
-
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
276
|
-
token_type: z3.string(),
|
|
277
|
-
expires_in: z3.number().optional(),
|
|
278
|
-
scope: z3.string().optional(),
|
|
279
|
-
refresh_token: z3.string().optional()
|
|
280
|
-
}).strip();
|
|
281
272
|
var SafeUrlSchema = z3.string().url().superRefine((val, ctx) => {
|
|
282
273
|
if (!URL.canParse(val)) {
|
|
283
274
|
ctx.addIssue({
|
|
@@ -294,6 +285,18 @@ var SafeUrlSchema = z3.string().url().superRefine((val, ctx) => {
|
|
|
294
285
|
},
|
|
295
286
|
{ message: "URL cannot use javascript:, data:, or vbscript: scheme" }
|
|
296
287
|
);
|
|
288
|
+
var OAuthTokensSchema = z3.object({
|
|
289
|
+
access_token: z3.string(),
|
|
290
|
+
id_token: z3.string().optional(),
|
|
291
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
292
|
+
token_type: z3.string(),
|
|
293
|
+
expires_in: z3.number().optional(),
|
|
294
|
+
scope: z3.string().optional(),
|
|
295
|
+
refresh_token: z3.string().optional(),
|
|
296
|
+
issuer: SafeUrlSchema.optional(),
|
|
297
|
+
authorization_server: SafeUrlSchema.optional(),
|
|
298
|
+
token_endpoint: SafeUrlSchema.optional()
|
|
299
|
+
}).strip();
|
|
297
300
|
var OAuthProtectedResourceMetadataSchema = z3.object({
|
|
298
301
|
resource: z3.string().url(),
|
|
299
302
|
authorization_servers: z3.array(SafeUrlSchema).optional(),
|
|
@@ -346,7 +349,10 @@ var OAuthClientInformationSchema = z3.object({
|
|
|
346
349
|
client_id: z3.string(),
|
|
347
350
|
client_secret: z3.string().optional(),
|
|
348
351
|
client_id_issued_at: z3.number().optional(),
|
|
349
|
-
client_secret_expires_at: z3.number().optional()
|
|
352
|
+
client_secret_expires_at: z3.number().optional(),
|
|
353
|
+
issuer: SafeUrlSchema.optional(),
|
|
354
|
+
authorization_server: SafeUrlSchema.optional(),
|
|
355
|
+
token_endpoint: SafeUrlSchema.optional()
|
|
350
356
|
}).strip();
|
|
351
357
|
var OAuthClientMetadataSchema = z3.object({
|
|
352
358
|
redirect_uris: z3.array(SafeUrlSchema),
|
|
@@ -449,6 +455,130 @@ var UnauthorizedError = class extends Error {
|
|
|
449
455
|
this.name = "UnauthorizedError";
|
|
450
456
|
}
|
|
451
457
|
};
|
|
458
|
+
function normalizeUrl(url) {
|
|
459
|
+
return new URL(url).href;
|
|
460
|
+
}
|
|
461
|
+
function validateAuthorizationResponseIssuer({
|
|
462
|
+
callbackIssuer,
|
|
463
|
+
expectedIssuer
|
|
464
|
+
}) {
|
|
465
|
+
if (callbackIssuer != null && callbackIssuer !== expectedIssuer) {
|
|
466
|
+
throw new MCPClientOAuthError({
|
|
467
|
+
message: `OAuth authorization response issuer ${callbackIssuer} does not match expected issuer ${expectedIssuer}`
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function createAuthorizationServerInformation(authorizationServerUrl, metadata) {
|
|
472
|
+
var _a3;
|
|
473
|
+
return {
|
|
474
|
+
issuer: (_a3 = metadata == null ? void 0 : metadata.issuer) != null ? _a3 : String(authorizationServerUrl),
|
|
475
|
+
authorizationServerUrl: normalizeUrl(authorizationServerUrl),
|
|
476
|
+
tokenEndpoint: normalizeUrl(
|
|
477
|
+
(metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl)
|
|
478
|
+
)
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function addAuthorizationServerInformationToTokens(tokens, authorizationServerInformation) {
|
|
482
|
+
return {
|
|
483
|
+
...tokens,
|
|
484
|
+
issuer: authorizationServerInformation.issuer,
|
|
485
|
+
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
486
|
+
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function addAuthorizationServerInformationToClientInformation(clientInformation, authorizationServerInformation) {
|
|
490
|
+
return {
|
|
491
|
+
...clientInformation,
|
|
492
|
+
issuer: authorizationServerInformation.issuer,
|
|
493
|
+
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
494
|
+
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function getAuthorizationServerInformationFromCredentials(credentials) {
|
|
498
|
+
if (!(credentials == null ? void 0 : credentials.authorization_server) || !credentials.token_endpoint) {
|
|
499
|
+
return void 0;
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
issuer: credentials.issuer,
|
|
503
|
+
authorizationServerUrl: normalizeUrl(credentials.authorization_server),
|
|
504
|
+
tokenEndpoint: normalizeUrl(credentials.token_endpoint)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
async function getStoredAuthorizationServerInformation({
|
|
508
|
+
provider,
|
|
509
|
+
clientInformation,
|
|
510
|
+
tokens
|
|
511
|
+
}) {
|
|
512
|
+
var _a3;
|
|
513
|
+
const tokenAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(tokens);
|
|
514
|
+
if (tokenAuthorizationServerInformation) {
|
|
515
|
+
return tokenAuthorizationServerInformation;
|
|
516
|
+
}
|
|
517
|
+
const providerAuthorizationServerInformation = await ((_a3 = provider.authorizationServerInformation) == null ? void 0 : _a3.call(provider));
|
|
518
|
+
if (providerAuthorizationServerInformation) {
|
|
519
|
+
return {
|
|
520
|
+
issuer: providerAuthorizationServerInformation.issuer,
|
|
521
|
+
authorizationServerUrl: normalizeUrl(
|
|
522
|
+
providerAuthorizationServerInformation.authorizationServerUrl
|
|
523
|
+
),
|
|
524
|
+
tokenEndpoint: normalizeUrl(
|
|
525
|
+
providerAuthorizationServerInformation.tokenEndpoint
|
|
526
|
+
)
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
return getAuthorizationServerInformationFromCredentials(clientInformation);
|
|
530
|
+
}
|
|
531
|
+
async function saveAuthorizationServerInformation({
|
|
532
|
+
provider,
|
|
533
|
+
clientInformation,
|
|
534
|
+
authorizationServerInformation
|
|
535
|
+
}) {
|
|
536
|
+
if (provider.saveAuthorizationServerInformation) {
|
|
537
|
+
await provider.saveAuthorizationServerInformation(
|
|
538
|
+
authorizationServerInformation
|
|
539
|
+
);
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
if (provider.saveClientInformation) {
|
|
543
|
+
await provider.saveClientInformation(
|
|
544
|
+
addAuthorizationServerInformationToClientInformation(
|
|
545
|
+
clientInformation,
|
|
546
|
+
authorizationServerInformation
|
|
547
|
+
)
|
|
548
|
+
);
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
const configuredBinding = getAuthorizationServerInformationFromCredentials(clientInformation);
|
|
552
|
+
if (configuredBinding) {
|
|
553
|
+
assertAuthorizationServerInformationMatches({
|
|
554
|
+
storedAuthorizationServerInformation: configuredBinding,
|
|
555
|
+
currentAuthorizationServerInformation: authorizationServerInformation
|
|
556
|
+
});
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
function assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl) {
|
|
562
|
+
if (!resourceMetadataUrl) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const expectedOrigin = new URL(serverUrl).origin;
|
|
566
|
+
if (resourceMetadataUrl.origin !== expectedOrigin) {
|
|
567
|
+
throw new MCPClientOAuthError({
|
|
568
|
+
message: `OAuth protected resource metadata URL ${resourceMetadataUrl.href} must have the same origin as the MCP server URL ${expectedOrigin}`
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function assertAuthorizationServerInformationMatches({
|
|
573
|
+
storedAuthorizationServerInformation,
|
|
574
|
+
currentAuthorizationServerInformation
|
|
575
|
+
}) {
|
|
576
|
+
if (storedAuthorizationServerInformation.issuer != null && currentAuthorizationServerInformation.issuer != null && storedAuthorizationServerInformation.issuer !== currentAuthorizationServerInformation.issuer || storedAuthorizationServerInformation.authorizationServerUrl !== currentAuthorizationServerInformation.authorizationServerUrl || storedAuthorizationServerInformation.tokenEndpoint !== currentAuthorizationServerInformation.tokenEndpoint) {
|
|
577
|
+
throw new MCPClientOAuthError({
|
|
578
|
+
message: "OAuth authorization server metadata does not match the metadata that issued the stored credentials"
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
452
582
|
function extractResourceMetadataUrl(response) {
|
|
453
583
|
var _a3;
|
|
454
584
|
const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
|
|
@@ -591,15 +721,18 @@ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn =
|
|
|
591
721
|
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
592
722
|
const url = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
593
723
|
const hasPath = url.pathname !== "/";
|
|
724
|
+
const rootIssuer = url.origin;
|
|
594
725
|
const urlsToTry = [];
|
|
595
726
|
if (!hasPath) {
|
|
596
727
|
urlsToTry.push({
|
|
597
728
|
url: new URL("/.well-known/oauth-authorization-server", url.origin),
|
|
598
|
-
type: "oauth"
|
|
729
|
+
type: "oauth",
|
|
730
|
+
expectedIssuer: rootIssuer
|
|
599
731
|
});
|
|
600
732
|
urlsToTry.push({
|
|
601
733
|
url: new URL("/.well-known/openid-configuration", url.origin),
|
|
602
|
-
type: "oidc"
|
|
734
|
+
type: "oidc",
|
|
735
|
+
expectedIssuer: rootIssuer
|
|
603
736
|
});
|
|
604
737
|
return urlsToTry;
|
|
605
738
|
}
|
|
@@ -607,27 +740,42 @@ function buildDiscoveryUrls(authorizationServerUrl) {
|
|
|
607
740
|
if (pathname.endsWith("/")) {
|
|
608
741
|
pathname = pathname.slice(0, -1);
|
|
609
742
|
}
|
|
743
|
+
const pathIssuer = `${url.origin}${pathname}`;
|
|
610
744
|
urlsToTry.push({
|
|
611
745
|
url: new URL(
|
|
612
746
|
`/.well-known/oauth-authorization-server${pathname}`,
|
|
613
747
|
url.origin
|
|
614
748
|
),
|
|
615
|
-
type: "oauth"
|
|
749
|
+
type: "oauth",
|
|
750
|
+
expectedIssuer: pathIssuer
|
|
616
751
|
});
|
|
617
752
|
urlsToTry.push({
|
|
618
753
|
url: new URL("/.well-known/oauth-authorization-server", url.origin),
|
|
619
|
-
type: "oauth"
|
|
754
|
+
type: "oauth",
|
|
755
|
+
expectedIssuer: rootIssuer
|
|
620
756
|
});
|
|
621
757
|
urlsToTry.push({
|
|
622
758
|
url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
|
|
623
|
-
type: "oidc"
|
|
759
|
+
type: "oidc",
|
|
760
|
+
expectedIssuer: pathIssuer
|
|
624
761
|
});
|
|
762
|
+
const oidcDiscoveryUrl = new URL(url.origin);
|
|
763
|
+
oidcDiscoveryUrl.pathname = `${pathname}/.well-known/openid-configuration`;
|
|
625
764
|
urlsToTry.push({
|
|
626
|
-
url:
|
|
627
|
-
type: "oidc"
|
|
765
|
+
url: oidcDiscoveryUrl,
|
|
766
|
+
type: "oidc",
|
|
767
|
+
expectedIssuer: pathIssuer
|
|
628
768
|
});
|
|
629
769
|
return urlsToTry;
|
|
630
770
|
}
|
|
771
|
+
function assertMetadataIssuerMatches(metadata, expectedIssuer) {
|
|
772
|
+
const issuerMatches = metadata.issuer === expectedIssuer || expectedIssuer === new URL(expectedIssuer).origin && metadata.issuer === `${expectedIssuer}/`;
|
|
773
|
+
if (!issuerMatches) {
|
|
774
|
+
throw new MCPClientOAuthError({
|
|
775
|
+
message: `OAuth authorization server metadata issuer ${metadata.issuer} does not match expected issuer ${expectedIssuer}`
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
}
|
|
631
779
|
async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
632
780
|
fetchFn = fetch,
|
|
633
781
|
protocolVersion = LATEST_PROTOCOL_VERSION,
|
|
@@ -635,8 +783,14 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
|
635
783
|
} = {}) {
|
|
636
784
|
var _a3;
|
|
637
785
|
const headers = { "MCP-Protocol-Version": protocolVersion };
|
|
786
|
+
const authorizationServerOrigin = new URL(authorizationServerUrl).origin;
|
|
638
787
|
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
639
|
-
|
|
788
|
+
if (urlsToTry.some(({ url }) => url.origin !== authorizationServerOrigin)) {
|
|
789
|
+
throw new MCPClientOAuthError({
|
|
790
|
+
message: "OAuth discovery URL changed authorization-server origin"
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
for (const { url: endpointUrl, type, expectedIssuer } of urlsToTry) {
|
|
640
794
|
const response = await fetchWithCorsRetry(
|
|
641
795
|
endpointUrl,
|
|
642
796
|
headers,
|
|
@@ -655,11 +809,14 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
|
655
809
|
);
|
|
656
810
|
}
|
|
657
811
|
if (type === "oauth") {
|
|
658
|
-
|
|
812
|
+
const metadata = OAuthMetadataSchema.parse(await response.json());
|
|
813
|
+
assertMetadataIssuerMatches(metadata, expectedIssuer);
|
|
814
|
+
return metadata;
|
|
659
815
|
} else {
|
|
660
816
|
const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(
|
|
661
817
|
await response.json()
|
|
662
818
|
);
|
|
819
|
+
assertMetadataIssuerMatches(metadata, expectedIssuer);
|
|
663
820
|
if (!((_a3 = metadata.code_challenge_methods_supported) == null ? void 0 : _a3.includes("S256"))) {
|
|
664
821
|
throw new Error(
|
|
665
822
|
`Incompatible OIDC provider at ${endpointUrl}: does not support S256 code challenge method required by MCP specification`
|
|
@@ -668,7 +825,6 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
|
668
825
|
return metadata;
|
|
669
826
|
}
|
|
670
827
|
}
|
|
671
|
-
return void 0;
|
|
672
828
|
}
|
|
673
829
|
async function startAuthorization(authorizationServerUrl, {
|
|
674
830
|
metadata,
|
|
@@ -950,16 +1106,28 @@ async function registerClient(authorizationServerUrl, {
|
|
|
950
1106
|
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
951
1107
|
}
|
|
952
1108
|
async function auth(provider, options) {
|
|
953
|
-
var _a3, _b3;
|
|
1109
|
+
var _a3, _b3, _c;
|
|
1110
|
+
const refreshAttempt = {};
|
|
954
1111
|
try {
|
|
955
|
-
return await authInternal(provider, options);
|
|
1112
|
+
return await authInternal(provider, options, refreshAttempt);
|
|
956
1113
|
} catch (error) {
|
|
957
1114
|
if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
|
|
958
|
-
await ((_a3 = provider.
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
await ((_b3 = provider.invalidateCredentials) == null ? void 0 : _b3.call(provider, "
|
|
1115
|
+
if (options.authorizationCode !== void 0 || !await ((_a3 = provider.isClientInformationDynamicallyRegistered) == null ? void 0 : _a3.call(provider))) {
|
|
1116
|
+
throw error;
|
|
1117
|
+
}
|
|
1118
|
+
await ((_b3 = provider.invalidateCredentials) == null ? void 0 : _b3.call(provider, "all"));
|
|
962
1119
|
return await authInternal(provider, options);
|
|
1120
|
+
} else if (error instanceof InvalidGrantError && refreshAttempt.tokens) {
|
|
1121
|
+
const retryAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(refreshAttempt.tokens);
|
|
1122
|
+
await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens", {
|
|
1123
|
+
tokens: refreshAttempt.tokens
|
|
1124
|
+
}));
|
|
1125
|
+
return await authInternal(
|
|
1126
|
+
provider,
|
|
1127
|
+
options,
|
|
1128
|
+
void 0,
|
|
1129
|
+
retryAuthorizationServerInformation
|
|
1130
|
+
);
|
|
963
1131
|
}
|
|
964
1132
|
throw error;
|
|
965
1133
|
}
|
|
@@ -988,12 +1156,18 @@ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
|
988
1156
|
async function authInternal(provider, {
|
|
989
1157
|
serverUrl,
|
|
990
1158
|
authorizationCode,
|
|
1159
|
+
callbackState,
|
|
1160
|
+
callbackIssuer,
|
|
991
1161
|
scope,
|
|
992
1162
|
resourceMetadataUrl,
|
|
993
1163
|
fetchFn
|
|
994
|
-
}) {
|
|
1164
|
+
}, refreshAttempt, retryAuthorizationServerInformation) {
|
|
1165
|
+
var _a3, _b3, _c, _d, _e, _f;
|
|
995
1166
|
let resourceMetadata;
|
|
996
1167
|
let authorizationServerUrl;
|
|
1168
|
+
let clientInformation;
|
|
1169
|
+
let callbackAuthorizationServerInformation;
|
|
1170
|
+
assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl);
|
|
997
1171
|
try {
|
|
998
1172
|
resourceMetadata = await discoverOAuthProtectedResourceMetadata(
|
|
999
1173
|
serverUrl,
|
|
@@ -1005,8 +1179,17 @@ async function authInternal(provider, {
|
|
|
1005
1179
|
}
|
|
1006
1180
|
} catch (e) {
|
|
1007
1181
|
}
|
|
1182
|
+
if (authorizationCode !== void 0) {
|
|
1183
|
+
clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1184
|
+
if (clientInformation) {
|
|
1185
|
+
callbackAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
1186
|
+
provider,
|
|
1187
|
+
clientInformation
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1008
1191
|
if (!authorizationServerUrl) {
|
|
1009
|
-
authorizationServerUrl = serverUrl;
|
|
1192
|
+
authorizationServerUrl = (_a3 = callbackAuthorizationServerInformation == null ? void 0 : callbackAuthorizationServerInformation.authorizationServerUrl) != null ? _a3 : serverUrl;
|
|
1010
1193
|
}
|
|
1011
1194
|
const parsedServerUrl = new URL(serverUrl);
|
|
1012
1195
|
const parsedAuthorizationServerUrl = new URL(authorizationServerUrl);
|
|
@@ -1021,6 +1204,11 @@ async function authInternal(provider, {
|
|
|
1021
1204
|
provider,
|
|
1022
1205
|
resourceMetadata
|
|
1023
1206
|
);
|
|
1207
|
+
await ((_b3 = provider.validateAuthorizationServerURL) == null ? void 0 : _b3.call(
|
|
1208
|
+
provider,
|
|
1209
|
+
serverUrl,
|
|
1210
|
+
authorizationServerUrl
|
|
1211
|
+
));
|
|
1024
1212
|
const metadata = await discoverAuthorizationServerMetadata(
|
|
1025
1213
|
authorizationServerUrl,
|
|
1026
1214
|
{
|
|
@@ -1028,7 +1216,59 @@ async function authInternal(provider, {
|
|
|
1028
1216
|
trustedOrigin: trustedAuthorizationServerOrigin
|
|
1029
1217
|
}
|
|
1030
1218
|
);
|
|
1031
|
-
|
|
1219
|
+
const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
|
|
1220
|
+
if (retryAuthorizationServerInformation) {
|
|
1221
|
+
assertAuthorizationServerInformationMatches({
|
|
1222
|
+
storedAuthorizationServerInformation: retryAuthorizationServerInformation,
|
|
1223
|
+
currentAuthorizationServerInformation
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
const clientMetadata = provider.clientMetadata;
|
|
1227
|
+
if (authorizationCode === void 0) {
|
|
1228
|
+
clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1229
|
+
}
|
|
1230
|
+
let tokens = authorizationCode === void 0 ? await provider.tokens() : void 0;
|
|
1231
|
+
if (clientInformation) {
|
|
1232
|
+
if (clientInformation.issuer != null && clientInformation.issuer !== currentAuthorizationServerInformation.issuer) {
|
|
1233
|
+
throw new MCPClientOAuthError({
|
|
1234
|
+
message: "OAuth authorization server does not match the issuer of the client credentials"
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
const clientAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(clientInformation);
|
|
1238
|
+
if (clientAuthorizationServerInformation) {
|
|
1239
|
+
assertAuthorizationServerInformationMatches({
|
|
1240
|
+
storedAuthorizationServerInformation: clientAuthorizationServerInformation,
|
|
1241
|
+
currentAuthorizationServerInformation
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
const storedAuthorizationServerInformation = (_c = callbackAuthorizationServerInformation != null ? callbackAuthorizationServerInformation : await getStoredAuthorizationServerInformation({
|
|
1245
|
+
provider,
|
|
1246
|
+
clientInformation,
|
|
1247
|
+
tokens
|
|
1248
|
+
})) != null ? _c : retryAuthorizationServerInformation;
|
|
1249
|
+
if (storedAuthorizationServerInformation) {
|
|
1250
|
+
assertAuthorizationServerInformationMatches({
|
|
1251
|
+
storedAuthorizationServerInformation,
|
|
1252
|
+
currentAuthorizationServerInformation
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
if ((clientInformation.client_secret != null || provider.addClientAuthentication) && clientInformation.issuer == null && !storedAuthorizationServerInformation) {
|
|
1256
|
+
if (authorizationCode === void 0 && await ((_d = provider.isClientInformationDynamicallyRegistered) == null ? void 0 : _d.call(provider))) {
|
|
1257
|
+
if (!provider.invalidateCredentials) {
|
|
1258
|
+
throw new MCPClientOAuthError({
|
|
1259
|
+
message: "invalidateCredentials is required to discard unbound legacy OAuth credentials; clear stored credentials before authorizing again"
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
await provider.invalidateCredentials("all");
|
|
1263
|
+
clientInformation = void 0;
|
|
1264
|
+
tokens = void 0;
|
|
1265
|
+
} else {
|
|
1266
|
+
throw new MCPClientOAuthError({
|
|
1267
|
+
message: "OAuth client credentials must be bound to an authorization server: configure their issuer or store authorization server information"
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1032
1272
|
if (!clientInformation) {
|
|
1033
1273
|
if (authorizationCode !== void 0) {
|
|
1034
1274
|
throw new Error(
|
|
@@ -1042,13 +1282,41 @@ async function authInternal(provider, {
|
|
|
1042
1282
|
}
|
|
1043
1283
|
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
1044
1284
|
metadata,
|
|
1045
|
-
clientMetadata
|
|
1285
|
+
clientMetadata,
|
|
1046
1286
|
fetchFn
|
|
1047
1287
|
});
|
|
1048
|
-
|
|
1049
|
-
|
|
1288
|
+
clientInformation = addAuthorizationServerInformationToClientInformation(
|
|
1289
|
+
fullInformation,
|
|
1290
|
+
currentAuthorizationServerInformation
|
|
1291
|
+
);
|
|
1292
|
+
await provider.saveClientInformation(clientInformation);
|
|
1050
1293
|
}
|
|
1051
1294
|
if (authorizationCode !== void 0) {
|
|
1295
|
+
if (provider.storedState) {
|
|
1296
|
+
const expectedState = await provider.storedState();
|
|
1297
|
+
if (expectedState !== void 0 && expectedState !== callbackState) {
|
|
1298
|
+
throw new Error(
|
|
1299
|
+
"OAuth state parameter mismatch - possible CSRF attack"
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
const storedAuthorizationServerInformation = callbackAuthorizationServerInformation != null ? callbackAuthorizationServerInformation : await getStoredAuthorizationServerInformation({
|
|
1304
|
+
provider,
|
|
1305
|
+
clientInformation
|
|
1306
|
+
});
|
|
1307
|
+
if (!storedAuthorizationServerInformation) {
|
|
1308
|
+
throw new MCPClientOAuthError({
|
|
1309
|
+
message: "Stored OAuth authorization server metadata is required when exchanging an authorization code"
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
validateAuthorizationResponseIssuer({
|
|
1313
|
+
callbackIssuer,
|
|
1314
|
+
expectedIssuer: (_f = (_e = storedAuthorizationServerInformation.issuer) != null ? _e : metadata == null ? void 0 : metadata.issuer) != null ? _f : String(authorizationServerUrl)
|
|
1315
|
+
});
|
|
1316
|
+
assertAuthorizationServerInformationMatches({
|
|
1317
|
+
storedAuthorizationServerInformation,
|
|
1318
|
+
currentAuthorizationServerInformation
|
|
1319
|
+
});
|
|
1052
1320
|
const codeVerifier2 = await provider.codeVerifier();
|
|
1053
1321
|
const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
|
|
1054
1322
|
metadata,
|
|
@@ -1060,22 +1328,56 @@ async function authInternal(provider, {
|
|
|
1060
1328
|
addClientAuthentication: provider.addClientAuthentication,
|
|
1061
1329
|
fetchFn
|
|
1062
1330
|
});
|
|
1063
|
-
await provider.saveTokens(
|
|
1331
|
+
await provider.saveTokens(
|
|
1332
|
+
addAuthorizationServerInformationToTokens(
|
|
1333
|
+
tokens2,
|
|
1334
|
+
currentAuthorizationServerInformation
|
|
1335
|
+
)
|
|
1336
|
+
);
|
|
1064
1337
|
return "AUTHORIZED";
|
|
1065
1338
|
}
|
|
1066
|
-
const tokens = await provider.tokens();
|
|
1067
1339
|
if (tokens == null ? void 0 : tokens.refresh_token) {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1340
|
+
const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
1341
|
+
provider,
|
|
1342
|
+
clientInformation,
|
|
1343
|
+
tokens
|
|
1344
|
+
});
|
|
1345
|
+
if (storedAuthorizationServerInformation) {
|
|
1346
|
+
assertAuthorizationServerInformationMatches({
|
|
1347
|
+
storedAuthorizationServerInformation,
|
|
1348
|
+
currentAuthorizationServerInformation
|
|
1076
1349
|
});
|
|
1077
|
-
|
|
1078
|
-
|
|
1350
|
+
} else {
|
|
1351
|
+
if (!provider.invalidateCredentials) {
|
|
1352
|
+
throw new MCPClientOAuthError({
|
|
1353
|
+
message: "invalidateCredentials is required to discard unbound legacy OAuth tokens; clear stored tokens before authorizing again"
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
await provider.invalidateCredentials("tokens", {
|
|
1357
|
+
tokens: { ...tokens }
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
try {
|
|
1361
|
+
if (storedAuthorizationServerInformation) {
|
|
1362
|
+
if (refreshAttempt) {
|
|
1363
|
+
refreshAttempt.tokens = { ...tokens };
|
|
1364
|
+
}
|
|
1365
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
1366
|
+
metadata,
|
|
1367
|
+
clientInformation,
|
|
1368
|
+
refreshToken: tokens.refresh_token,
|
|
1369
|
+
resource,
|
|
1370
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
1371
|
+
fetchFn
|
|
1372
|
+
});
|
|
1373
|
+
await provider.saveTokens(
|
|
1374
|
+
addAuthorizationServerInformationToTokens(
|
|
1375
|
+
newTokens,
|
|
1376
|
+
currentAuthorizationServerInformation
|
|
1377
|
+
)
|
|
1378
|
+
);
|
|
1379
|
+
return "AUTHORIZED";
|
|
1380
|
+
}
|
|
1079
1381
|
} catch (error) {
|
|
1080
1382
|
if (
|
|
1081
1383
|
// If this is a ServerError, or an unknown type, log it out and try to continue. Otherwise, escalate so we can fix things and retry.
|
|
@@ -1087,6 +1389,9 @@ async function authInternal(provider, {
|
|
|
1087
1389
|
}
|
|
1088
1390
|
}
|
|
1089
1391
|
const state = provider.state ? await provider.state() : void 0;
|
|
1392
|
+
if (state && provider.saveState) {
|
|
1393
|
+
await provider.saveState(state);
|
|
1394
|
+
}
|
|
1090
1395
|
const { authorizationUrl, codeVerifier } = await startAuthorization(
|
|
1091
1396
|
authorizationServerUrl,
|
|
1092
1397
|
{
|
|
@@ -1094,10 +1399,20 @@ async function authInternal(provider, {
|
|
|
1094
1399
|
clientInformation,
|
|
1095
1400
|
state,
|
|
1096
1401
|
redirectUrl: provider.redirectUrl,
|
|
1097
|
-
scope: scope ||
|
|
1402
|
+
scope: scope || clientMetadata.scope,
|
|
1098
1403
|
resource
|
|
1099
1404
|
}
|
|
1100
1405
|
);
|
|
1406
|
+
const savedAuthorizationServerInformation = await saveAuthorizationServerInformation({
|
|
1407
|
+
provider,
|
|
1408
|
+
clientInformation,
|
|
1409
|
+
authorizationServerInformation: currentAuthorizationServerInformation
|
|
1410
|
+
});
|
|
1411
|
+
if (!savedAuthorizationServerInformation) {
|
|
1412
|
+
throw new MCPClientOAuthError({
|
|
1413
|
+
message: "OAuth authorization server metadata must be saveable before starting authorization"
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1101
1416
|
await provider.saveCodeVerifier(codeVerifier);
|
|
1102
1417
|
await provider.redirectToAuthorization(authorizationUrl);
|
|
1103
1418
|
return "REDIRECT";
|