@lanonasis/oauth-client 1.0.0 → 1.0.2
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.cjs +35 -8
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +35 -8
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -378,7 +378,11 @@ var TokenStorage = class {
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
async store(tokens) {
|
|
381
|
-
const
|
|
381
|
+
const tokensWithTimestamp = {
|
|
382
|
+
...tokens,
|
|
383
|
+
issued_at: Date.now()
|
|
384
|
+
};
|
|
385
|
+
const tokenString = JSON.stringify(tokensWithTimestamp);
|
|
382
386
|
if (this.isNode()) {
|
|
383
387
|
if (this.keytar) {
|
|
384
388
|
await this.keytar.setPassword("lanonasis-mcp", "tokens", tokenString);
|
|
@@ -386,7 +390,7 @@ var TokenStorage = class {
|
|
|
386
390
|
await this.storeToFile(tokenString);
|
|
387
391
|
}
|
|
388
392
|
} else if (this.isElectron()) {
|
|
389
|
-
await window.electronAPI.secureStore.set(this.storageKey,
|
|
393
|
+
await window.electronAPI.secureStore.set(this.storageKey, tokensWithTimestamp);
|
|
390
394
|
} else if (this.isMobile()) {
|
|
391
395
|
await window.SecureStorage.set(this.storageKey, tokenString);
|
|
392
396
|
} else {
|
|
@@ -437,15 +441,14 @@ var TokenStorage = class {
|
|
|
437
441
|
}
|
|
438
442
|
isTokenExpired(tokens) {
|
|
439
443
|
if (!tokens.expires_in) return false;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
444
|
+
if (!tokens.issued_at) {
|
|
445
|
+
console.warn("Token missing issued_at timestamp, treating as expired");
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
|
|
443
449
|
const now = Date.now();
|
|
444
450
|
return expiresAt - now < 3e5;
|
|
445
451
|
}
|
|
446
|
-
getStoredAt(tokens) {
|
|
447
|
-
return Date.now() - 36e5;
|
|
448
|
-
}
|
|
449
452
|
async storeToFile(tokenString) {
|
|
450
453
|
if (!this.isNode()) return;
|
|
451
454
|
const fs = require("fs").promises;
|
|
@@ -1118,6 +1121,29 @@ var MCPClient = class {
|
|
|
1118
1121
|
await this.tokenStorage.store(tokens);
|
|
1119
1122
|
return tokens;
|
|
1120
1123
|
}
|
|
1124
|
+
async ensureAccessToken() {
|
|
1125
|
+
if (this.accessToken) return;
|
|
1126
|
+
const tokens = await this.tokenStorage.retrieve();
|
|
1127
|
+
if (!tokens) {
|
|
1128
|
+
throw new Error("Not authenticated");
|
|
1129
|
+
}
|
|
1130
|
+
if (this.tokenStorage.isTokenExpired(tokens)) {
|
|
1131
|
+
if (tokens.refresh_token) {
|
|
1132
|
+
try {
|
|
1133
|
+
const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
|
|
1134
|
+
await this.tokenStorage.store(newTokens);
|
|
1135
|
+
this.accessToken = newTokens.access_token;
|
|
1136
|
+
return;
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
console.error("Token refresh failed:", error);
|
|
1139
|
+
throw new Error("Token expired and refresh failed");
|
|
1140
|
+
}
|
|
1141
|
+
} else {
|
|
1142
|
+
throw new Error("Token expired and no refresh token available");
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
this.accessToken = tokens.access_token;
|
|
1146
|
+
}
|
|
1121
1147
|
scheduleTokenRefresh(tokens) {
|
|
1122
1148
|
if (this.refreshTimer) {
|
|
1123
1149
|
clearTimeout(this.refreshTimer);
|
|
@@ -1225,6 +1251,7 @@ var MCPClient = class {
|
|
|
1225
1251
|
await this.establishConnection();
|
|
1226
1252
|
}
|
|
1227
1253
|
async request(method, params) {
|
|
1254
|
+
await this.ensureAccessToken();
|
|
1228
1255
|
if (!this.accessToken) {
|
|
1229
1256
|
throw new Error("Not authenticated");
|
|
1230
1257
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
interface TokenResponse {
|
|
2
2
|
access_token: string;
|
|
3
|
-
token_type: string;
|
|
4
|
-
expires_in: number;
|
|
5
3
|
refresh_token?: string;
|
|
6
|
-
|
|
4
|
+
expires_in: number;
|
|
5
|
+
token_type: string;
|
|
6
|
+
scope?: string;
|
|
7
|
+
issued_at?: number;
|
|
7
8
|
}
|
|
8
9
|
interface DeviceCodeResponse {
|
|
9
10
|
device_code: string;
|
|
@@ -77,8 +78,9 @@ declare class TokenStorage {
|
|
|
77
78
|
store(tokens: TokenResponse): Promise<void>;
|
|
78
79
|
retrieve(): Promise<TokenResponse | null>;
|
|
79
80
|
clear(): Promise<void>;
|
|
80
|
-
isTokenExpired(tokens: TokenResponse
|
|
81
|
-
|
|
81
|
+
isTokenExpired(tokens: TokenResponse & {
|
|
82
|
+
issued_at?: number;
|
|
83
|
+
}): boolean;
|
|
82
84
|
private storeToFile;
|
|
83
85
|
private retrieveFromFile;
|
|
84
86
|
private deleteFile;
|
|
@@ -182,6 +184,7 @@ declare class MCPClient {
|
|
|
182
184
|
constructor(config?: MCPClientConfig);
|
|
183
185
|
connect(): Promise<void>;
|
|
184
186
|
private authenticate;
|
|
187
|
+
private ensureAccessToken;
|
|
185
188
|
private scheduleTokenRefresh;
|
|
186
189
|
private establishConnection;
|
|
187
190
|
private connectWebSocket;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
interface TokenResponse {
|
|
2
2
|
access_token: string;
|
|
3
|
-
token_type: string;
|
|
4
|
-
expires_in: number;
|
|
5
3
|
refresh_token?: string;
|
|
6
|
-
|
|
4
|
+
expires_in: number;
|
|
5
|
+
token_type: string;
|
|
6
|
+
scope?: string;
|
|
7
|
+
issued_at?: number;
|
|
7
8
|
}
|
|
8
9
|
interface DeviceCodeResponse {
|
|
9
10
|
device_code: string;
|
|
@@ -77,8 +78,9 @@ declare class TokenStorage {
|
|
|
77
78
|
store(tokens: TokenResponse): Promise<void>;
|
|
78
79
|
retrieve(): Promise<TokenResponse | null>;
|
|
79
80
|
clear(): Promise<void>;
|
|
80
|
-
isTokenExpired(tokens: TokenResponse
|
|
81
|
-
|
|
81
|
+
isTokenExpired(tokens: TokenResponse & {
|
|
82
|
+
issued_at?: number;
|
|
83
|
+
}): boolean;
|
|
82
84
|
private storeToFile;
|
|
83
85
|
private retrieveFromFile;
|
|
84
86
|
private deleteFile;
|
|
@@ -182,6 +184,7 @@ declare class MCPClient {
|
|
|
182
184
|
constructor(config?: MCPClientConfig);
|
|
183
185
|
connect(): Promise<void>;
|
|
184
186
|
private authenticate;
|
|
187
|
+
private ensureAccessToken;
|
|
185
188
|
private scheduleTokenRefresh;
|
|
186
189
|
private establishConnection;
|
|
187
190
|
private connectWebSocket;
|
package/dist/index.js
CHANGED
|
@@ -344,7 +344,11 @@ var TokenStorage = class {
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
async store(tokens) {
|
|
347
|
-
const
|
|
347
|
+
const tokensWithTimestamp = {
|
|
348
|
+
...tokens,
|
|
349
|
+
issued_at: Date.now()
|
|
350
|
+
};
|
|
351
|
+
const tokenString = JSON.stringify(tokensWithTimestamp);
|
|
348
352
|
if (this.isNode()) {
|
|
349
353
|
if (this.keytar) {
|
|
350
354
|
await this.keytar.setPassword("lanonasis-mcp", "tokens", tokenString);
|
|
@@ -352,7 +356,7 @@ var TokenStorage = class {
|
|
|
352
356
|
await this.storeToFile(tokenString);
|
|
353
357
|
}
|
|
354
358
|
} else if (this.isElectron()) {
|
|
355
|
-
await window.electronAPI.secureStore.set(this.storageKey,
|
|
359
|
+
await window.electronAPI.secureStore.set(this.storageKey, tokensWithTimestamp);
|
|
356
360
|
} else if (this.isMobile()) {
|
|
357
361
|
await window.SecureStorage.set(this.storageKey, tokenString);
|
|
358
362
|
} else {
|
|
@@ -403,15 +407,14 @@ var TokenStorage = class {
|
|
|
403
407
|
}
|
|
404
408
|
isTokenExpired(tokens) {
|
|
405
409
|
if (!tokens.expires_in) return false;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
410
|
+
if (!tokens.issued_at) {
|
|
411
|
+
console.warn("Token missing issued_at timestamp, treating as expired");
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
|
|
409
415
|
const now = Date.now();
|
|
410
416
|
return expiresAt - now < 3e5;
|
|
411
417
|
}
|
|
412
|
-
getStoredAt(tokens) {
|
|
413
|
-
return Date.now() - 36e5;
|
|
414
|
-
}
|
|
415
418
|
async storeToFile(tokenString) {
|
|
416
419
|
if (!this.isNode()) return;
|
|
417
420
|
const fs = __require("fs").promises;
|
|
@@ -1084,6 +1087,29 @@ var MCPClient = class {
|
|
|
1084
1087
|
await this.tokenStorage.store(tokens);
|
|
1085
1088
|
return tokens;
|
|
1086
1089
|
}
|
|
1090
|
+
async ensureAccessToken() {
|
|
1091
|
+
if (this.accessToken) return;
|
|
1092
|
+
const tokens = await this.tokenStorage.retrieve();
|
|
1093
|
+
if (!tokens) {
|
|
1094
|
+
throw new Error("Not authenticated");
|
|
1095
|
+
}
|
|
1096
|
+
if (this.tokenStorage.isTokenExpired(tokens)) {
|
|
1097
|
+
if (tokens.refresh_token) {
|
|
1098
|
+
try {
|
|
1099
|
+
const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
|
|
1100
|
+
await this.tokenStorage.store(newTokens);
|
|
1101
|
+
this.accessToken = newTokens.access_token;
|
|
1102
|
+
return;
|
|
1103
|
+
} catch (error) {
|
|
1104
|
+
console.error("Token refresh failed:", error);
|
|
1105
|
+
throw new Error("Token expired and refresh failed");
|
|
1106
|
+
}
|
|
1107
|
+
} else {
|
|
1108
|
+
throw new Error("Token expired and no refresh token available");
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
this.accessToken = tokens.access_token;
|
|
1112
|
+
}
|
|
1087
1113
|
scheduleTokenRefresh(tokens) {
|
|
1088
1114
|
if (this.refreshTimer) {
|
|
1089
1115
|
clearTimeout(this.refreshTimer);
|
|
@@ -1191,6 +1217,7 @@ var MCPClient = class {
|
|
|
1191
1217
|
await this.establishConnection();
|
|
1192
1218
|
}
|
|
1193
1219
|
async request(method, params) {
|
|
1220
|
+
await this.ensureAccessToken();
|
|
1194
1221
|
if (!this.accessToken) {
|
|
1195
1222
|
throw new Error("Not authenticated");
|
|
1196
1223
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lanonasis/oauth-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OAuth client for Lan Onasis MCP integration",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
],
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/lanonasis/
|
|
19
|
-
"directory": "
|
|
18
|
+
"url": "git+https://github.com/lanonasis/v-secure.git",
|
|
19
|
+
"directory": "oauth-client"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/lanonasis/
|
|
22
|
+
"url": "https://github.com/lanonasis/v-secure/issues"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.com/lanonasis/
|
|
24
|
+
"homepage": "https://github.com/lanonasis/v-secure/tree/main/oauth-client",
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
27
|
"types": "./dist/index.d.ts",
|