integrate-sdk 0.3.14 → 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 +129 -108
- package/dist/oauth.js +27 -23
- package/dist/server.js +129 -108
- package/dist/src/adapters/auto-routes.d.ts.map +1 -1
- package/dist/src/adapters/base-handler.d.ts +13 -12
- package/dist/src/adapters/base-handler.d.ts.map +1 -1
- package/dist/src/adapters/nextjs.d.ts +3 -4
- 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 +1 -1
- 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,16 +244,16 @@ class OAuthHandler {
|
|
|
245
244
|
const data = await response.json();
|
|
246
245
|
return data;
|
|
247
246
|
}
|
|
248
|
-
async handleDisconnect(request,
|
|
249
|
-
if (!
|
|
250
|
-
throw new Error("No
|
|
247
|
+
async handleDisconnect(request, accessToken) {
|
|
248
|
+
if (!accessToken) {
|
|
249
|
+
throw new Error("No access token provided. Cannot disconnect provider.");
|
|
251
250
|
}
|
|
252
251
|
const url = new URL("/oauth/disconnect", this.serverUrl);
|
|
253
252
|
const response = await fetch(url.toString(), {
|
|
254
253
|
method: "POST",
|
|
255
254
|
headers: {
|
|
256
255
|
"Content-Type": "application/json",
|
|
257
|
-
|
|
256
|
+
Authorization: `Bearer ${accessToken}`
|
|
258
257
|
},
|
|
259
258
|
body: JSON.stringify({
|
|
260
259
|
provider: request.provider
|
|
@@ -301,14 +300,15 @@ function createNextOAuthHandler(config) {
|
|
|
301
300
|
async status(req) {
|
|
302
301
|
try {
|
|
303
302
|
const provider = req.nextUrl.searchParams.get("provider");
|
|
304
|
-
const
|
|
303
|
+
const authHeader = req.headers.get("authorization");
|
|
305
304
|
if (!provider) {
|
|
306
305
|
return Response.json({ error: "Missing provider query parameter" }, { status: 400 });
|
|
307
306
|
}
|
|
308
|
-
if (!
|
|
309
|
-
return Response.json({ error: "Missing
|
|
307
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
308
|
+
return Response.json({ error: "Missing or invalid Authorization header" }, { status: 400 });
|
|
310
309
|
}
|
|
311
|
-
const
|
|
310
|
+
const accessToken = authHeader.substring(7);
|
|
311
|
+
const result = await handler.handleStatus(provider, accessToken);
|
|
312
312
|
return Response.json(result);
|
|
313
313
|
} catch (error) {
|
|
314
314
|
console.error("[OAuth Status] Error:", error);
|
|
@@ -317,16 +317,17 @@ function createNextOAuthHandler(config) {
|
|
|
317
317
|
},
|
|
318
318
|
async disconnect(req) {
|
|
319
319
|
try {
|
|
320
|
-
const
|
|
321
|
-
if (!
|
|
322
|
-
return Response.json({ error: "Missing
|
|
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
323
|
}
|
|
324
|
+
const accessToken = authHeader.substring(7);
|
|
324
325
|
const body = await req.json();
|
|
325
326
|
const { provider } = body;
|
|
326
327
|
if (!provider) {
|
|
327
328
|
return Response.json({ error: "Missing provider in request body" }, { status: 400 });
|
|
328
329
|
}
|
|
329
|
-
const result = await handler.handleDisconnect({ provider },
|
|
330
|
+
const result = await handler.handleDisconnect({ provider }, accessToken);
|
|
330
331
|
return Response.json(result);
|
|
331
332
|
} catch (error) {
|
|
332
333
|
console.error("[OAuth Disconnect] Error:", error);
|
|
@@ -824,7 +825,7 @@ function sendCallbackToOpener(params) {
|
|
|
824
825
|
// src/oauth/manager.ts
|
|
825
826
|
class OAuthManager {
|
|
826
827
|
pendingAuths = new Map;
|
|
827
|
-
|
|
828
|
+
providerTokens = new Map;
|
|
828
829
|
windowManager;
|
|
829
830
|
flowConfig;
|
|
830
831
|
oauthApiBase;
|
|
@@ -890,11 +891,19 @@ class OAuthManager {
|
|
|
890
891
|
}
|
|
891
892
|
try {
|
|
892
893
|
const response = await this.exchangeCodeForToken(pendingAuth.provider, code, pendingAuth.codeVerifier, state);
|
|
893
|
-
|
|
894
|
-
|
|
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);
|
|
895
904
|
this.pendingAuths.delete(state);
|
|
896
905
|
this.removePendingAuthFromStorage(state);
|
|
897
|
-
return
|
|
906
|
+
return { ...tokenData, provider: pendingAuth.provider };
|
|
898
907
|
} catch (error) {
|
|
899
908
|
this.pendingAuths.delete(state);
|
|
900
909
|
this.removePendingAuthFromStorage(state);
|
|
@@ -902,7 +911,8 @@ class OAuthManager {
|
|
|
902
911
|
}
|
|
903
912
|
}
|
|
904
913
|
async checkAuthStatus(provider) {
|
|
905
|
-
|
|
914
|
+
const tokenData = this.providerTokens.get(provider);
|
|
915
|
+
if (!tokenData) {
|
|
906
916
|
return {
|
|
907
917
|
authorized: false,
|
|
908
918
|
provider
|
|
@@ -913,7 +923,7 @@ class OAuthManager {
|
|
|
913
923
|
const response = await fetch(url, {
|
|
914
924
|
method: "GET",
|
|
915
925
|
headers: {
|
|
916
|
-
|
|
926
|
+
Authorization: `Bearer ${tokenData.accessToken}`
|
|
917
927
|
}
|
|
918
928
|
});
|
|
919
929
|
if (!response.ok) {
|
|
@@ -923,7 +933,7 @@ class OAuthManager {
|
|
|
923
933
|
};
|
|
924
934
|
}
|
|
925
935
|
const status = await response.json();
|
|
926
|
-
return status;
|
|
936
|
+
return { ...status, provider };
|
|
927
937
|
} catch (error) {
|
|
928
938
|
console.error("Failed to check auth status:", error);
|
|
929
939
|
return {
|
|
@@ -933,8 +943,9 @@ class OAuthManager {
|
|
|
933
943
|
}
|
|
934
944
|
}
|
|
935
945
|
async disconnectProvider(provider) {
|
|
936
|
-
|
|
937
|
-
|
|
946
|
+
const tokenData = this.providerTokens.get(provider);
|
|
947
|
+
if (!tokenData) {
|
|
948
|
+
throw new Error(`No access token available for provider "${provider}". Cannot disconnect provider.`);
|
|
938
949
|
}
|
|
939
950
|
try {
|
|
940
951
|
const url = `${this.oauthApiBase}/disconnect`;
|
|
@@ -942,7 +953,7 @@ class OAuthManager {
|
|
|
942
953
|
method: "POST",
|
|
943
954
|
headers: {
|
|
944
955
|
"Content-Type": "application/json",
|
|
945
|
-
|
|
956
|
+
Authorization: `Bearer ${tokenData.accessToken}`
|
|
946
957
|
},
|
|
947
958
|
body: JSON.stringify({ provider })
|
|
948
959
|
});
|
|
@@ -950,25 +961,43 @@ class OAuthManager {
|
|
|
950
961
|
const errorText = await response.text();
|
|
951
962
|
throw new Error(`Failed to disconnect provider: ${errorText}`);
|
|
952
963
|
}
|
|
964
|
+
this.providerTokens.delete(provider);
|
|
965
|
+
this.clearProviderToken(provider);
|
|
953
966
|
} catch (error) {
|
|
954
967
|
console.error("Failed to disconnect provider:", error);
|
|
955
968
|
throw error;
|
|
956
969
|
}
|
|
957
970
|
}
|
|
958
|
-
|
|
959
|
-
return this.
|
|
971
|
+
getProviderToken(provider) {
|
|
972
|
+
return this.providerTokens.get(provider);
|
|
960
973
|
}
|
|
961
|
-
|
|
962
|
-
this.
|
|
963
|
-
this.saveSessionToken(token);
|
|
974
|
+
getAllProviderTokens() {
|
|
975
|
+
return new Map(this.providerTokens);
|
|
964
976
|
}
|
|
965
|
-
|
|
966
|
-
this.
|
|
967
|
-
|
|
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) {
|
|
968
984
|
try {
|
|
969
|
-
window.
|
|
985
|
+
window.localStorage.removeItem(`integrate_token_${provider}`);
|
|
970
986
|
} catch (error) {
|
|
971
|
-
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
|
+
}
|
|
972
1001
|
}
|
|
973
1002
|
}
|
|
974
1003
|
}
|
|
@@ -990,12 +1019,35 @@ class OAuthManager {
|
|
|
990
1019
|
}
|
|
991
1020
|
}
|
|
992
1021
|
}
|
|
993
|
-
|
|
994
|
-
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) {
|
|
995
1034
|
try {
|
|
996
|
-
|
|
1035
|
+
const key = `integrate_token_${provider}`;
|
|
1036
|
+
const stored = window.localStorage.getItem(key);
|
|
1037
|
+
if (stored) {
|
|
1038
|
+
return JSON.parse(stored);
|
|
1039
|
+
}
|
|
997
1040
|
} catch (error) {
|
|
998
|
-
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);
|
|
999
1051
|
}
|
|
1000
1052
|
}
|
|
1001
1053
|
}
|
|
@@ -1183,23 +1235,15 @@ class MCPClient {
|
|
|
1183
1235
|
this.maxReauthRetries = config.maxReauthRetries ?? 1;
|
|
1184
1236
|
this.connectionMode = config.connectionMode ?? "lazy";
|
|
1185
1237
|
this.oauthManager = new OAuthManager(config.oauthApiBase || "/api/integrate/oauth", config.oauthFlow);
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
const storedToken = this.loadSessionToken();
|
|
1189
|
-
if (storedToken) {
|
|
1190
|
-
sessionToken = storedToken;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
if (sessionToken) {
|
|
1194
|
-
this.oauthManager.setSessionToken(sessionToken);
|
|
1195
|
-
this.transport.setHeader("X-Session-Token", sessionToken);
|
|
1196
|
-
}
|
|
1238
|
+
const providers = this.plugins.filter((p) => p.oauth).map((p) => p.oauth.provider);
|
|
1239
|
+
this.oauthManager.loadAllProviderTokens(providers);
|
|
1197
1240
|
for (const plugin of this.plugins) {
|
|
1198
1241
|
for (const toolName of plugin.tools) {
|
|
1199
1242
|
this.enabledToolNames.add(toolName);
|
|
1200
1243
|
}
|
|
1201
1244
|
if (plugin.oauth) {
|
|
1202
|
-
this.
|
|
1245
|
+
const hasToken = this.oauthManager.getProviderToken(plugin.oauth.provider) !== undefined;
|
|
1246
|
+
this.authState.set(plugin.oauth.provider, { authenticated: hasToken });
|
|
1203
1247
|
}
|
|
1204
1248
|
}
|
|
1205
1249
|
this.github = this.createPluginProxy("github");
|
|
@@ -1340,30 +1384,36 @@ class MCPClient {
|
|
|
1340
1384
|
if (!this.availableTools.has(name)) {
|
|
1341
1385
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1342
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
|
+
}
|
|
1343
1394
|
const params = {
|
|
1344
1395
|
name,
|
|
1345
1396
|
arguments: args
|
|
1346
1397
|
};
|
|
1347
1398
|
try {
|
|
1348
1399
|
const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
|
|
1349
|
-
const provider = this.getProviderForTool(name);
|
|
1350
1400
|
if (provider) {
|
|
1351
1401
|
this.authState.set(provider, { authenticated: true });
|
|
1352
1402
|
}
|
|
1353
1403
|
return response;
|
|
1354
1404
|
} catch (error) {
|
|
1355
|
-
const
|
|
1356
|
-
const parsedError = parseServerError(error, { toolName: name, provider });
|
|
1405
|
+
const provider2 = this.getProviderForTool(name);
|
|
1406
|
+
const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
|
|
1357
1407
|
if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
|
|
1358
|
-
if (
|
|
1359
|
-
this.authState.set(
|
|
1408
|
+
if (provider2) {
|
|
1409
|
+
this.authState.set(provider2, {
|
|
1360
1410
|
authenticated: false,
|
|
1361
1411
|
lastError: parsedError
|
|
1362
1412
|
});
|
|
1363
1413
|
}
|
|
1364
|
-
if (this.onReauthRequired &&
|
|
1414
|
+
if (this.onReauthRequired && provider2) {
|
|
1365
1415
|
const reauthSuccess = await this.onReauthRequired({
|
|
1366
|
-
provider,
|
|
1416
|
+
provider: provider2,
|
|
1367
1417
|
error: parsedError,
|
|
1368
1418
|
toolName: name
|
|
1369
1419
|
});
|
|
@@ -1414,35 +1464,8 @@ class MCPClient {
|
|
|
1414
1464
|
off(event, handler) {
|
|
1415
1465
|
this.eventEmitter.off(event, handler);
|
|
1416
1466
|
}
|
|
1417
|
-
saveSessionToken(token) {
|
|
1418
|
-
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
1419
|
-
try {
|
|
1420
|
-
window.sessionStorage.setItem("integrate_session_token", token);
|
|
1421
|
-
} catch (error) {
|
|
1422
|
-
console.error("Failed to save session token to sessionStorage:", error);
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
loadSessionToken() {
|
|
1427
|
-
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
1428
|
-
try {
|
|
1429
|
-
return window.sessionStorage.getItem("integrate_session_token") || undefined;
|
|
1430
|
-
} catch (error) {
|
|
1431
|
-
console.error("Failed to load session token from sessionStorage:", error);
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
return;
|
|
1436
|
-
}
|
|
1437
1467
|
clearSessionToken() {
|
|
1438
|
-
|
|
1439
|
-
try {
|
|
1440
|
-
window.sessionStorage.removeItem("integrate_session_token");
|
|
1441
|
-
} catch (error) {
|
|
1442
|
-
console.error("Failed to clear session token from sessionStorage:", error);
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
this.oauthManager.clearSessionToken();
|
|
1468
|
+
this.oauthManager.clearAllProviderTokens();
|
|
1446
1469
|
}
|
|
1447
1470
|
async disconnectProvider(provider) {
|
|
1448
1471
|
const plugin = this.plugins.find((p) => p.oauth?.provider === provider);
|
|
@@ -1522,10 +1545,13 @@ class MCPClient {
|
|
|
1522
1545
|
this.eventEmitter.emit("auth:started", { provider });
|
|
1523
1546
|
try {
|
|
1524
1547
|
await this.oauthManager.initiateFlow(provider, plugin.oauth);
|
|
1525
|
-
const
|
|
1526
|
-
if (
|
|
1527
|
-
this.
|
|
1528
|
-
|
|
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
|
+
});
|
|
1529
1555
|
}
|
|
1530
1556
|
this.authState.set(provider, { authenticated: true });
|
|
1531
1557
|
} catch (error) {
|
|
@@ -1535,18 +1561,13 @@ class MCPClient {
|
|
|
1535
1561
|
}
|
|
1536
1562
|
async handleOAuthCallback(params) {
|
|
1537
1563
|
try {
|
|
1538
|
-
const
|
|
1539
|
-
this.
|
|
1540
|
-
this.
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
provider: plugin.oauth.provider,
|
|
1546
|
-
sessionToken
|
|
1547
|
-
});
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
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
|
+
});
|
|
1550
1571
|
} catch (error) {
|
|
1551
1572
|
this.eventEmitter.emit("auth:error", {
|
|
1552
1573
|
provider: "unknown",
|
|
@@ -1555,12 +1576,12 @@ class MCPClient {
|
|
|
1555
1576
|
throw error;
|
|
1556
1577
|
}
|
|
1557
1578
|
}
|
|
1558
|
-
|
|
1559
|
-
return this.oauthManager.
|
|
1579
|
+
getProviderToken(provider) {
|
|
1580
|
+
return this.oauthManager.getProviderToken(provider);
|
|
1560
1581
|
}
|
|
1561
|
-
|
|
1562
|
-
this.oauthManager.
|
|
1563
|
-
this.
|
|
1582
|
+
setProviderToken(provider, tokenData) {
|
|
1583
|
+
this.oauthManager.setProviderToken(provider, tokenData);
|
|
1584
|
+
this.authState.set(provider, { authenticated: true });
|
|
1564
1585
|
}
|
|
1565
1586
|
async reauthenticate(provider) {
|
|
1566
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,16 +106,16 @@ class OAuthHandler {
|
|
|
107
106
|
const data = await response.json();
|
|
108
107
|
return data;
|
|
109
108
|
}
|
|
110
|
-
async handleDisconnect(request,
|
|
111
|
-
if (!
|
|
112
|
-
throw new Error("No
|
|
109
|
+
async handleDisconnect(request, accessToken) {
|
|
110
|
+
if (!accessToken) {
|
|
111
|
+
throw new Error("No access token provided. Cannot disconnect provider.");
|
|
113
112
|
}
|
|
114
113
|
const url = new URL("/oauth/disconnect", this.serverUrl);
|
|
115
114
|
const response = await fetch(url.toString(), {
|
|
116
115
|
method: "POST",
|
|
117
116
|
headers: {
|
|
118
117
|
"Content-Type": "application/json",
|
|
119
|
-
|
|
118
|
+
Authorization: `Bearer ${accessToken}`
|
|
120
119
|
},
|
|
121
120
|
body: JSON.stringify({
|
|
122
121
|
provider: request.provider
|
|
@@ -156,14 +155,14 @@ async function POST(req, context) {
|
|
|
156
155
|
}
|
|
157
156
|
if (action === "disconnect") {
|
|
158
157
|
const body = await parseRequestBody(req);
|
|
159
|
-
const
|
|
160
|
-
if (!
|
|
161
|
-
return createErrorResponse("Missing
|
|
158
|
+
const accessToken = extractAccessToken(req);
|
|
159
|
+
if (!accessToken) {
|
|
160
|
+
return createErrorResponse("Missing or invalid Authorization header", 400);
|
|
162
161
|
}
|
|
163
162
|
if (!body.provider) {
|
|
164
163
|
return createErrorResponse("Missing provider in request body", 400);
|
|
165
164
|
}
|
|
166
|
-
const result = await handler.handleDisconnect({ provider: body.provider },
|
|
165
|
+
const result = await handler.handleDisconnect({ provider: body.provider }, accessToken);
|
|
167
166
|
return createSuccessResponse(result);
|
|
168
167
|
}
|
|
169
168
|
return createErrorResponse(`Unknown action: ${action}`, 404);
|
|
@@ -183,11 +182,15 @@ async function GET(req, context) {
|
|
|
183
182
|
}
|
|
184
183
|
try {
|
|
185
184
|
if (action === "status") {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
const provider = extractProvider(req);
|
|
186
|
+
const accessToken = extractAccessToken(req);
|
|
187
|
+
if (!provider) {
|
|
188
|
+
return createErrorResponse("Missing provider parameter", 400);
|
|
189
189
|
}
|
|
190
|
-
|
|
190
|
+
if (!accessToken) {
|
|
191
|
+
return createErrorResponse("Missing or invalid Authorization header", 400);
|
|
192
|
+
}
|
|
193
|
+
const result = await handler.handleStatus(provider, accessToken);
|
|
191
194
|
return createSuccessResponse(result);
|
|
192
195
|
}
|
|
193
196
|
return createErrorResponse(`Unknown action: ${action}`, 404);
|
|
@@ -202,24 +205,25 @@ async function parseRequestBody(req) {
|
|
|
202
205
|
}
|
|
203
206
|
throw new Error("Unable to parse request body");
|
|
204
207
|
}
|
|
205
|
-
function
|
|
208
|
+
function extractAccessToken(req) {
|
|
206
209
|
if (req.headers?.get) {
|
|
207
|
-
|
|
210
|
+
const authHeader = req.headers.get("authorization");
|
|
211
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
212
|
+
return authHeader.substring(7);
|
|
213
|
+
}
|
|
208
214
|
}
|
|
209
215
|
return;
|
|
210
216
|
}
|
|
211
|
-
function
|
|
217
|
+
function extractProvider(req) {
|
|
212
218
|
let url;
|
|
213
219
|
if (req.nextUrl) {
|
|
214
220
|
url = new URL(req.nextUrl);
|
|
215
221
|
} else if (req.url) {
|
|
216
222
|
url = new URL(req.url);
|
|
217
223
|
} else {
|
|
218
|
-
return
|
|
224
|
+
return;
|
|
219
225
|
}
|
|
220
|
-
|
|
221
|
-
const sessionToken = extractSessionToken(req);
|
|
222
|
-
return { provider, sessionToken };
|
|
226
|
+
return url.searchParams.get("provider") || undefined;
|
|
223
227
|
}
|
|
224
228
|
function createSuccessResponse(data) {
|
|
225
229
|
if (typeof globalThis.NextResponse !== "undefined") {
|