integrate-sdk 0.3.13 → 0.4.1
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/index.js +164 -100
- package/dist/oauth.js +57 -13
- package/dist/server.js +164 -100
- package/dist/src/adapters/auto-routes.d.ts +1 -1
- package/dist/src/adapters/auto-routes.d.ts.map +1 -1
- package/dist/src/adapters/base-handler.d.ts +35 -9
- package/dist/src/adapters/base-handler.d.ts.map +1 -1
- package/dist/src/adapters/nextjs.d.ts +48 -5
- package/dist/src/adapters/nextjs.d.ts.map +1 -1
- package/dist/src/client.d.ts +11 -21
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/oauth/manager.d.ts +33 -13
- package/dist/src/oauth/manager.d.ts.map +1 -1
- package/dist/src/oauth/types.d.ts +33 -6
- package/dist/src/oauth/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -223,20 +223,19 @@ class OAuthHandler {
|
|
|
223
223
|
const data = await response.json();
|
|
224
224
|
return data;
|
|
225
225
|
}
|
|
226
|
-
async handleStatus(provider,
|
|
226
|
+
async handleStatus(provider, accessToken) {
|
|
227
227
|
const url = new URL("/oauth/status", this.serverUrl);
|
|
228
228
|
url.searchParams.set("provider", provider);
|
|
229
229
|
const response = await fetch(url.toString(), {
|
|
230
230
|
method: "GET",
|
|
231
231
|
headers: {
|
|
232
|
-
|
|
232
|
+
Authorization: `Bearer ${accessToken}`
|
|
233
233
|
}
|
|
234
234
|
});
|
|
235
235
|
if (!response.ok) {
|
|
236
236
|
if (response.status === 401) {
|
|
237
237
|
return {
|
|
238
|
-
authorized: false
|
|
239
|
-
provider
|
|
238
|
+
authorized: false
|
|
240
239
|
};
|
|
241
240
|
}
|
|
242
241
|
const error = await response.text();
|
|
@@ -245,6 +244,28 @@ class OAuthHandler {
|
|
|
245
244
|
const data = await response.json();
|
|
246
245
|
return data;
|
|
247
246
|
}
|
|
247
|
+
async handleDisconnect(request, accessToken) {
|
|
248
|
+
if (!accessToken) {
|
|
249
|
+
throw new Error("No access token provided. Cannot disconnect provider.");
|
|
250
|
+
}
|
|
251
|
+
const url = new URL("/oauth/disconnect", this.serverUrl);
|
|
252
|
+
const response = await fetch(url.toString(), {
|
|
253
|
+
method: "POST",
|
|
254
|
+
headers: {
|
|
255
|
+
"Content-Type": "application/json",
|
|
256
|
+
Authorization: `Bearer ${accessToken}`
|
|
257
|
+
},
|
|
258
|
+
body: JSON.stringify({
|
|
259
|
+
provider: request.provider
|
|
260
|
+
})
|
|
261
|
+
});
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
const error = await response.text();
|
|
264
|
+
throw new Error(`MCP server failed to disconnect provider: ${error}`);
|
|
265
|
+
}
|
|
266
|
+
const data = await response.json();
|
|
267
|
+
return data;
|
|
268
|
+
}
|
|
248
269
|
}
|
|
249
270
|
var MCP_SERVER_URL2 = "https://mcp.integrate.dev/api/v1/mcp";
|
|
250
271
|
|
|
@@ -279,20 +300,40 @@ function createNextOAuthHandler(config) {
|
|
|
279
300
|
async status(req) {
|
|
280
301
|
try {
|
|
281
302
|
const provider = req.nextUrl.searchParams.get("provider");
|
|
282
|
-
const
|
|
303
|
+
const authHeader = req.headers.get("authorization");
|
|
283
304
|
if (!provider) {
|
|
284
305
|
return Response.json({ error: "Missing provider query parameter" }, { status: 400 });
|
|
285
306
|
}
|
|
286
|
-
if (!
|
|
287
|
-
return Response.json({ error: "Missing
|
|
307
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
308
|
+
return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
|
|
288
309
|
}
|
|
289
|
-
const
|
|
310
|
+
const accessToken = authHeader.substring(7);
|
|
311
|
+
const result = await handler.handleStatus(provider, accessToken);
|
|
290
312
|
return Response.json(result);
|
|
291
313
|
} catch (error) {
|
|
292
314
|
console.error("[OAuth Status] Error:", error);
|
|
293
315
|
return Response.json({ error: error.message || "Failed to check authorization status" }, { status: 500 });
|
|
294
316
|
}
|
|
295
317
|
},
|
|
318
|
+
async disconnect(req) {
|
|
319
|
+
try {
|
|
320
|
+
const authHeader = req.headers.get("authorization");
|
|
321
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
322
|
+
return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
|
|
323
|
+
}
|
|
324
|
+
const accessToken = authHeader.substring(7);
|
|
325
|
+
const body = await req.json();
|
|
326
|
+
const { provider } = body;
|
|
327
|
+
if (!provider) {
|
|
328
|
+
return Response.json({ error: "Missing provider in request body" }, { status: 400 });
|
|
329
|
+
}
|
|
330
|
+
const result = await handler.handleDisconnect({ provider }, accessToken);
|
|
331
|
+
return Response.json(result);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error("[OAuth Disconnect] Error:", error);
|
|
334
|
+
return Response.json({ error: error.message || "Failed to disconnect provider" }, { status: 500 });
|
|
335
|
+
}
|
|
336
|
+
},
|
|
296
337
|
createRoutes() {
|
|
297
338
|
return {
|
|
298
339
|
async POST(req, context) {
|
|
@@ -304,6 +345,9 @@ function createNextOAuthHandler(config) {
|
|
|
304
345
|
if (action === "callback") {
|
|
305
346
|
return handlers.callback(req);
|
|
306
347
|
}
|
|
348
|
+
if (action === "disconnect") {
|
|
349
|
+
return handlers.disconnect(req);
|
|
350
|
+
}
|
|
307
351
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
308
352
|
},
|
|
309
353
|
async GET(req, context) {
|
|
@@ -781,7 +825,7 @@ function sendCallbackToOpener(params) {
|
|
|
781
825
|
// src/oauth/manager.ts
|
|
782
826
|
class OAuthManager {
|
|
783
827
|
pendingAuths = new Map;
|
|
784
|
-
|
|
828
|
+
providerTokens = new Map;
|
|
785
829
|
windowManager;
|
|
786
830
|
flowConfig;
|
|
787
831
|
oauthApiBase;
|
|
@@ -847,11 +891,19 @@ class OAuthManager {
|
|
|
847
891
|
}
|
|
848
892
|
try {
|
|
849
893
|
const response = await this.exchangeCodeForToken(pendingAuth.provider, code, pendingAuth.codeVerifier, state);
|
|
850
|
-
|
|
851
|
-
|
|
894
|
+
const tokenData = {
|
|
895
|
+
accessToken: response.accessToken,
|
|
896
|
+
refreshToken: response.refreshToken,
|
|
897
|
+
tokenType: response.tokenType,
|
|
898
|
+
expiresIn: response.expiresIn,
|
|
899
|
+
expiresAt: response.expiresAt,
|
|
900
|
+
scopes: response.scopes
|
|
901
|
+
};
|
|
902
|
+
this.providerTokens.set(pendingAuth.provider, tokenData);
|
|
903
|
+
this.saveProviderToken(pendingAuth.provider, tokenData);
|
|
852
904
|
this.pendingAuths.delete(state);
|
|
853
905
|
this.removePendingAuthFromStorage(state);
|
|
854
|
-
return
|
|
906
|
+
return { ...tokenData, provider: pendingAuth.provider };
|
|
855
907
|
} catch (error) {
|
|
856
908
|
this.pendingAuths.delete(state);
|
|
857
909
|
this.removePendingAuthFromStorage(state);
|
|
@@ -859,7 +911,8 @@ class OAuthManager {
|
|
|
859
911
|
}
|
|
860
912
|
}
|
|
861
913
|
async checkAuthStatus(provider) {
|
|
862
|
-
|
|
914
|
+
const tokenData = this.providerTokens.get(provider);
|
|
915
|
+
if (!tokenData) {
|
|
863
916
|
return {
|
|
864
917
|
authorized: false,
|
|
865
918
|
provider
|
|
@@ -870,7 +923,7 @@ class OAuthManager {
|
|
|
870
923
|
const response = await fetch(url, {
|
|
871
924
|
method: "GET",
|
|
872
925
|
headers: {
|
|
873
|
-
|
|
926
|
+
Authorization: `Bearer ${tokenData.accessToken}`
|
|
874
927
|
}
|
|
875
928
|
});
|
|
876
929
|
if (!response.ok) {
|
|
@@ -880,7 +933,7 @@ class OAuthManager {
|
|
|
880
933
|
};
|
|
881
934
|
}
|
|
882
935
|
const status = await response.json();
|
|
883
|
-
return status;
|
|
936
|
+
return { ...status, provider };
|
|
884
937
|
} catch (error) {
|
|
885
938
|
console.error("Failed to check auth status:", error);
|
|
886
939
|
return {
|
|
@@ -890,8 +943,9 @@ class OAuthManager {
|
|
|
890
943
|
}
|
|
891
944
|
}
|
|
892
945
|
async disconnectProvider(provider) {
|
|
893
|
-
|
|
894
|
-
|
|
946
|
+
const tokenData = this.providerTokens.get(provider);
|
|
947
|
+
if (!tokenData) {
|
|
948
|
+
throw new Error(`No access token available for provider "${provider}". Cannot disconnect provider.`);
|
|
895
949
|
}
|
|
896
950
|
try {
|
|
897
951
|
const url = `${this.oauthApiBase}/disconnect`;
|
|
@@ -899,7 +953,7 @@ class OAuthManager {
|
|
|
899
953
|
method: "POST",
|
|
900
954
|
headers: {
|
|
901
955
|
"Content-Type": "application/json",
|
|
902
|
-
|
|
956
|
+
Authorization: `Bearer ${tokenData.accessToken}`
|
|
903
957
|
},
|
|
904
958
|
body: JSON.stringify({ provider })
|
|
905
959
|
});
|
|
@@ -907,25 +961,43 @@ class OAuthManager {
|
|
|
907
961
|
const errorText = await response.text();
|
|
908
962
|
throw new Error(`Failed to disconnect provider: ${errorText}`);
|
|
909
963
|
}
|
|
964
|
+
this.providerTokens.delete(provider);
|
|
965
|
+
this.clearProviderToken(provider);
|
|
910
966
|
} catch (error) {
|
|
911
967
|
console.error("Failed to disconnect provider:", error);
|
|
912
968
|
throw error;
|
|
913
969
|
}
|
|
914
970
|
}
|
|
915
|
-
|
|
916
|
-
return this.
|
|
971
|
+
getProviderToken(provider) {
|
|
972
|
+
return this.providerTokens.get(provider);
|
|
917
973
|
}
|
|
918
|
-
|
|
919
|
-
this.
|
|
920
|
-
this.saveSessionToken(token);
|
|
974
|
+
getAllProviderTokens() {
|
|
975
|
+
return new Map(this.providerTokens);
|
|
921
976
|
}
|
|
922
|
-
|
|
923
|
-
this.
|
|
924
|
-
|
|
977
|
+
setProviderToken(provider, tokenData) {
|
|
978
|
+
this.providerTokens.set(provider, tokenData);
|
|
979
|
+
this.saveProviderToken(provider, tokenData);
|
|
980
|
+
}
|
|
981
|
+
clearProviderToken(provider) {
|
|
982
|
+
this.providerTokens.delete(provider);
|
|
983
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
925
984
|
try {
|
|
926
|
-
window.
|
|
985
|
+
window.localStorage.removeItem(`integrate_token_${provider}`);
|
|
927
986
|
} catch (error) {
|
|
928
|
-
console.error(
|
|
987
|
+
console.error(`Failed to clear token for ${provider} from localStorage:`, error);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
clearAllProviderTokens() {
|
|
992
|
+
const providers = Array.from(this.providerTokens.keys());
|
|
993
|
+
this.providerTokens.clear();
|
|
994
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
995
|
+
for (const provider of providers) {
|
|
996
|
+
try {
|
|
997
|
+
window.localStorage.removeItem(`integrate_token_${provider}`);
|
|
998
|
+
} catch (error) {
|
|
999
|
+
console.error(`Failed to clear token for ${provider} from localStorage:`, error);
|
|
1000
|
+
}
|
|
929
1001
|
}
|
|
930
1002
|
}
|
|
931
1003
|
}
|
|
@@ -947,12 +1019,35 @@ class OAuthManager {
|
|
|
947
1019
|
}
|
|
948
1020
|
}
|
|
949
1021
|
}
|
|
950
|
-
|
|
951
|
-
if (typeof window !== "undefined" && window.
|
|
1022
|
+
saveProviderToken(provider, tokenData) {
|
|
1023
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
1024
|
+
try {
|
|
1025
|
+
const key = `integrate_token_${provider}`;
|
|
1026
|
+
window.localStorage.setItem(key, JSON.stringify(tokenData));
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
console.error(`Failed to save token for ${provider} to localStorage:`, error);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
loadProviderToken(provider) {
|
|
1033
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
952
1034
|
try {
|
|
953
|
-
|
|
1035
|
+
const key = `integrate_token_${provider}`;
|
|
1036
|
+
const stored = window.localStorage.getItem(key);
|
|
1037
|
+
if (stored) {
|
|
1038
|
+
return JSON.parse(stored);
|
|
1039
|
+
}
|
|
954
1040
|
} catch (error) {
|
|
955
|
-
console.error(
|
|
1041
|
+
console.error(`Failed to load token for ${provider} from localStorage:`, error);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
loadAllProviderTokens(providers) {
|
|
1047
|
+
for (const provider of providers) {
|
|
1048
|
+
const tokenData = this.loadProviderToken(provider);
|
|
1049
|
+
if (tokenData) {
|
|
1050
|
+
this.providerTokens.set(provider, tokenData);
|
|
956
1051
|
}
|
|
957
1052
|
}
|
|
958
1053
|
}
|
|
@@ -1140,23 +1235,15 @@ class MCPClient {
|
|
|
1140
1235
|
this.maxReauthRetries = config.maxReauthRetries ?? 1;
|
|
1141
1236
|
this.connectionMode = config.connectionMode ?? "lazy";
|
|
1142
1237
|
this.oauthManager = new OAuthManager(config.oauthApiBase || "/api/integrate/oauth", config.oauthFlow);
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
const storedToken = this.loadSessionToken();
|
|
1146
|
-
if (storedToken) {
|
|
1147
|
-
sessionToken = storedToken;
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
if (sessionToken) {
|
|
1151
|
-
this.oauthManager.setSessionToken(sessionToken);
|
|
1152
|
-
this.transport.setHeader("X-Session-Token", sessionToken);
|
|
1153
|
-
}
|
|
1238
|
+
const providers = this.plugins.filter((p) => p.oauth).map((p) => p.oauth.provider);
|
|
1239
|
+
this.oauthManager.loadAllProviderTokens(providers);
|
|
1154
1240
|
for (const plugin of this.plugins) {
|
|
1155
1241
|
for (const toolName of plugin.tools) {
|
|
1156
1242
|
this.enabledToolNames.add(toolName);
|
|
1157
1243
|
}
|
|
1158
1244
|
if (plugin.oauth) {
|
|
1159
|
-
this.
|
|
1245
|
+
const hasToken = this.oauthManager.getProviderToken(plugin.oauth.provider) !== undefined;
|
|
1246
|
+
this.authState.set(plugin.oauth.provider, { authenticated: hasToken });
|
|
1160
1247
|
}
|
|
1161
1248
|
}
|
|
1162
1249
|
this.github = this.createPluginProxy("github");
|
|
@@ -1297,30 +1384,36 @@ class MCPClient {
|
|
|
1297
1384
|
if (!this.availableTools.has(name)) {
|
|
1298
1385
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1299
1386
|
}
|
|
1387
|
+
const provider = this.getProviderForTool(name);
|
|
1388
|
+
if (provider) {
|
|
1389
|
+
const tokenData = this.oauthManager.getProviderToken(provider);
|
|
1390
|
+
if (tokenData) {
|
|
1391
|
+
this.transport.setHeader("Authorization", `Bearer ${tokenData.accessToken}`);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1300
1394
|
const params = {
|
|
1301
1395
|
name,
|
|
1302
1396
|
arguments: args
|
|
1303
1397
|
};
|
|
1304
1398
|
try {
|
|
1305
1399
|
const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
|
|
1306
|
-
const provider = this.getProviderForTool(name);
|
|
1307
1400
|
if (provider) {
|
|
1308
1401
|
this.authState.set(provider, { authenticated: true });
|
|
1309
1402
|
}
|
|
1310
1403
|
return response;
|
|
1311
1404
|
} catch (error) {
|
|
1312
|
-
const
|
|
1313
|
-
const parsedError = parseServerError(error, { toolName: name, provider });
|
|
1405
|
+
const provider2 = this.getProviderForTool(name);
|
|
1406
|
+
const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
|
|
1314
1407
|
if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
|
|
1315
|
-
if (
|
|
1316
|
-
this.authState.set(
|
|
1408
|
+
if (provider2) {
|
|
1409
|
+
this.authState.set(provider2, {
|
|
1317
1410
|
authenticated: false,
|
|
1318
1411
|
lastError: parsedError
|
|
1319
1412
|
});
|
|
1320
1413
|
}
|
|
1321
|
-
if (this.onReauthRequired &&
|
|
1414
|
+
if (this.onReauthRequired && provider2) {
|
|
1322
1415
|
const reauthSuccess = await this.onReauthRequired({
|
|
1323
|
-
provider,
|
|
1416
|
+
provider: provider2,
|
|
1324
1417
|
error: parsedError,
|
|
1325
1418
|
toolName: name
|
|
1326
1419
|
});
|
|
@@ -1371,35 +1464,8 @@ class MCPClient {
|
|
|
1371
1464
|
off(event, handler) {
|
|
1372
1465
|
this.eventEmitter.off(event, handler);
|
|
1373
1466
|
}
|
|
1374
|
-
saveSessionToken(token) {
|
|
1375
|
-
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
1376
|
-
try {
|
|
1377
|
-
window.sessionStorage.setItem("integrate_session_token", token);
|
|
1378
|
-
} catch (error) {
|
|
1379
|
-
console.error("Failed to save session token to sessionStorage:", error);
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
loadSessionToken() {
|
|
1384
|
-
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
1385
|
-
try {
|
|
1386
|
-
return window.sessionStorage.getItem("integrate_session_token") || undefined;
|
|
1387
|
-
} catch (error) {
|
|
1388
|
-
console.error("Failed to load session token from sessionStorage:", error);
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
return;
|
|
1393
|
-
}
|
|
1394
1467
|
clearSessionToken() {
|
|
1395
|
-
|
|
1396
|
-
try {
|
|
1397
|
-
window.sessionStorage.removeItem("integrate_session_token");
|
|
1398
|
-
} catch (error) {
|
|
1399
|
-
console.error("Failed to clear session token from sessionStorage:", error);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
this.oauthManager.clearSessionToken();
|
|
1468
|
+
this.oauthManager.clearAllProviderTokens();
|
|
1403
1469
|
}
|
|
1404
1470
|
async disconnectProvider(provider) {
|
|
1405
1471
|
const plugin = this.plugins.find((p) => p.oauth?.provider === provider);
|
|
@@ -1479,10 +1545,13 @@ class MCPClient {
|
|
|
1479
1545
|
this.eventEmitter.emit("auth:started", { provider });
|
|
1480
1546
|
try {
|
|
1481
1547
|
await this.oauthManager.initiateFlow(provider, plugin.oauth);
|
|
1482
|
-
const
|
|
1483
|
-
if (
|
|
1484
|
-
this.
|
|
1485
|
-
|
|
1548
|
+
const tokenData = this.oauthManager.getProviderToken(provider);
|
|
1549
|
+
if (tokenData) {
|
|
1550
|
+
this.eventEmitter.emit("auth:complete", {
|
|
1551
|
+
provider,
|
|
1552
|
+
accessToken: tokenData.accessToken,
|
|
1553
|
+
expiresAt: tokenData.expiresAt
|
|
1554
|
+
});
|
|
1486
1555
|
}
|
|
1487
1556
|
this.authState.set(provider, { authenticated: true });
|
|
1488
1557
|
} catch (error) {
|
|
@@ -1492,18 +1561,13 @@ class MCPClient {
|
|
|
1492
1561
|
}
|
|
1493
1562
|
async handleOAuthCallback(params) {
|
|
1494
1563
|
try {
|
|
1495
|
-
const
|
|
1496
|
-
this.
|
|
1497
|
-
this.
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
provider: plugin.oauth.provider,
|
|
1503
|
-
sessionToken
|
|
1504
|
-
});
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1564
|
+
const result = await this.oauthManager.handleCallback(params.code, params.state);
|
|
1565
|
+
this.authState.set(result.provider, { authenticated: true });
|
|
1566
|
+
this.eventEmitter.emit("auth:complete", {
|
|
1567
|
+
provider: result.provider,
|
|
1568
|
+
accessToken: result.accessToken,
|
|
1569
|
+
expiresAt: result.expiresAt
|
|
1570
|
+
});
|
|
1507
1571
|
} catch (error) {
|
|
1508
1572
|
this.eventEmitter.emit("auth:error", {
|
|
1509
1573
|
provider: "unknown",
|
|
@@ -1512,12 +1576,12 @@ class MCPClient {
|
|
|
1512
1576
|
throw error;
|
|
1513
1577
|
}
|
|
1514
1578
|
}
|
|
1515
|
-
|
|
1516
|
-
return this.oauthManager.
|
|
1579
|
+
getProviderToken(provider) {
|
|
1580
|
+
return this.oauthManager.getProviderToken(provider);
|
|
1517
1581
|
}
|
|
1518
|
-
|
|
1519
|
-
this.oauthManager.
|
|
1520
|
-
this.
|
|
1582
|
+
setProviderToken(provider, tokenData) {
|
|
1583
|
+
this.oauthManager.setProviderToken(provider, tokenData);
|
|
1584
|
+
this.authState.set(provider, { authenticated: true });
|
|
1521
1585
|
}
|
|
1522
1586
|
async reauthenticate(provider) {
|
|
1523
1587
|
const state = this.authState.get(provider);
|
package/dist/oauth.js
CHANGED
|
@@ -85,20 +85,19 @@ class OAuthHandler {
|
|
|
85
85
|
const data = await response.json();
|
|
86
86
|
return data;
|
|
87
87
|
}
|
|
88
|
-
async handleStatus(provider,
|
|
88
|
+
async handleStatus(provider, accessToken) {
|
|
89
89
|
const url = new URL("/oauth/status", this.serverUrl);
|
|
90
90
|
url.searchParams.set("provider", provider);
|
|
91
91
|
const response = await fetch(url.toString(), {
|
|
92
92
|
method: "GET",
|
|
93
93
|
headers: {
|
|
94
|
-
|
|
94
|
+
Authorization: `Bearer ${accessToken}`
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
if (!response.ok) {
|
|
98
98
|
if (response.status === 401) {
|
|
99
99
|
return {
|
|
100
|
-
authorized: false
|
|
101
|
-
provider
|
|
100
|
+
authorized: false
|
|
102
101
|
};
|
|
103
102
|
}
|
|
104
103
|
const error = await response.text();
|
|
@@ -107,6 +106,28 @@ class OAuthHandler {
|
|
|
107
106
|
const data = await response.json();
|
|
108
107
|
return data;
|
|
109
108
|
}
|
|
109
|
+
async handleDisconnect(request, accessToken) {
|
|
110
|
+
if (!accessToken) {
|
|
111
|
+
throw new Error("No access token provided. Cannot disconnect provider.");
|
|
112
|
+
}
|
|
113
|
+
const url = new URL("/oauth/disconnect", this.serverUrl);
|
|
114
|
+
const response = await fetch(url.toString(), {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: {
|
|
117
|
+
"Content-Type": "application/json",
|
|
118
|
+
Authorization: `Bearer ${accessToken}`
|
|
119
|
+
},
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
provider: request.provider
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
const error = await response.text();
|
|
126
|
+
throw new Error(`MCP server failed to disconnect provider: ${error}`);
|
|
127
|
+
}
|
|
128
|
+
const data = await response.json();
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
110
131
|
}
|
|
111
132
|
var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
|
|
112
133
|
|
|
@@ -132,6 +153,18 @@ async function POST(req, context) {
|
|
|
132
153
|
const result = await handler.handleCallback(body);
|
|
133
154
|
return createSuccessResponse(result);
|
|
134
155
|
}
|
|
156
|
+
if (action === "disconnect") {
|
|
157
|
+
const body = await parseRequestBody(req);
|
|
158
|
+
const accessToken = extractAccessToken(req);
|
|
159
|
+
if (!accessToken) {
|
|
160
|
+
return createErrorResponse("Missing or invalid Authorization header", 400);
|
|
161
|
+
}
|
|
162
|
+
if (!body.provider) {
|
|
163
|
+
return createErrorResponse("Missing provider in request body", 400);
|
|
164
|
+
}
|
|
165
|
+
const result = await handler.handleDisconnect({ provider: body.provider }, accessToken);
|
|
166
|
+
return createSuccessResponse(result);
|
|
167
|
+
}
|
|
135
168
|
return createErrorResponse(`Unknown action: ${action}`, 404);
|
|
136
169
|
} catch (error) {
|
|
137
170
|
console.error(`[OAuth ${action}] Error:`, error);
|
|
@@ -149,11 +182,15 @@ async function GET(req, context) {
|
|
|
149
182
|
}
|
|
150
183
|
try {
|
|
151
184
|
if (action === "status") {
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
185
|
+
const provider = extractProvider(req);
|
|
186
|
+
const accessToken = extractAccessToken(req);
|
|
187
|
+
if (!provider) {
|
|
188
|
+
return createErrorResponse("Missing provider parameter", 400);
|
|
189
|
+
}
|
|
190
|
+
if (!accessToken) {
|
|
191
|
+
return createErrorResponse("Missing or invalid Authorization header", 400);
|
|
155
192
|
}
|
|
156
|
-
const result = await handler.handleStatus(provider,
|
|
193
|
+
const result = await handler.handleStatus(provider, accessToken);
|
|
157
194
|
return createSuccessResponse(result);
|
|
158
195
|
}
|
|
159
196
|
return createErrorResponse(`Unknown action: ${action}`, 404);
|
|
@@ -168,18 +205,25 @@ async function parseRequestBody(req) {
|
|
|
168
205
|
}
|
|
169
206
|
throw new Error("Unable to parse request body");
|
|
170
207
|
}
|
|
171
|
-
function
|
|
208
|
+
function extractAccessToken(req) {
|
|
209
|
+
if (req.headers?.get) {
|
|
210
|
+
const authHeader = req.headers.get("authorization");
|
|
211
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
212
|
+
return authHeader.substring(7);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
function extractProvider(req) {
|
|
172
218
|
let url;
|
|
173
219
|
if (req.nextUrl) {
|
|
174
220
|
url = new URL(req.nextUrl);
|
|
175
221
|
} else if (req.url) {
|
|
176
222
|
url = new URL(req.url);
|
|
177
223
|
} else {
|
|
178
|
-
return
|
|
224
|
+
return;
|
|
179
225
|
}
|
|
180
|
-
|
|
181
|
-
const sessionToken = req.headers?.get?.("x-session-token") || undefined;
|
|
182
|
-
return { provider, sessionToken };
|
|
226
|
+
return url.searchParams.get("provider") || undefined;
|
|
183
227
|
}
|
|
184
228
|
function createSuccessResponse(data) {
|
|
185
229
|
if (typeof globalThis.NextResponse !== "undefined") {
|