@unifiedmemory/cli 1.3.10 → 1.3.11
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/commands/login.js +3 -1
- package/lib/token-validation.js +75 -20
- package/package.json +1 -1
package/commands/login.js
CHANGED
|
@@ -222,6 +222,7 @@ export async function login() {
|
|
|
222
222
|
);
|
|
223
223
|
|
|
224
224
|
// Update saved token with org-scoped version
|
|
225
|
+
// Preserve originalSid for recovery purposes (org-scoped token won't have sid)
|
|
225
226
|
saveToken({
|
|
226
227
|
accessToken: tokenData.access_token,
|
|
227
228
|
idToken: orgToken.jwt,
|
|
@@ -230,7 +231,8 @@ export async function login() {
|
|
|
230
231
|
expiresIn: tokenData.expires_in,
|
|
231
232
|
receivedAt: Date.now(),
|
|
232
233
|
decoded: parseJWT(orgToken.jwt),
|
|
233
|
-
selectedOrg: selectedOrg
|
|
234
|
+
selectedOrg: selectedOrg,
|
|
235
|
+
originalSid: decoded.sid // Preserve session ID from original OAuth token
|
|
234
236
|
});
|
|
235
237
|
|
|
236
238
|
console.log(chalk.green(`\n✅ Using organization context: ${chalk.bold(selectedOrg.name)}`));
|
package/lib/token-validation.js
CHANGED
|
@@ -2,6 +2,7 @@ import { getToken, saveToken } from './token-storage.js';
|
|
|
2
2
|
import { isTokenExpired, refreshAccessToken } from './token-refresh.js';
|
|
3
3
|
import { getOrgScopedToken } from './clerk-api.js';
|
|
4
4
|
import { parseJWT } from './jwt-utils.js';
|
|
5
|
+
import { config } from './config.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Load token and refresh if expired
|
|
@@ -47,28 +48,82 @@ export async function loadAndRefreshToken(requireAuth = true) {
|
|
|
47
48
|
|
|
48
49
|
// Check if token has org context but lacks org claims in JWT
|
|
49
50
|
// This can happen if getOrgScopedToken() failed during login
|
|
50
|
-
if (tokenData.selectedOrg?.id &&
|
|
51
|
+
if (tokenData.selectedOrg?.id && !tokenData.decoded?.o) {
|
|
51
52
|
console.error('⚠️ Token missing org claims, attempting to fix...');
|
|
52
|
-
try {
|
|
53
|
-
const orgToken = await getOrgScopedToken(
|
|
54
|
-
tokenData.decoded.sid,
|
|
55
|
-
tokenData.selectedOrg.id,
|
|
56
|
-
tokenData.idToken || tokenData.accessToken
|
|
57
|
-
);
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
// Check for sid in decoded token or preserved originalSid from login
|
|
55
|
+
let sessionId = tokenData.decoded?.sid || tokenData.originalSid;
|
|
56
|
+
let currentToken = tokenData.idToken || tokenData.accessToken;
|
|
57
|
+
|
|
58
|
+
// If no sid, try to refresh first to get a new base token with sid
|
|
59
|
+
if (!sessionId && tokenData.refresh_token) {
|
|
60
|
+
console.error(' Refreshing to obtain session ID...');
|
|
61
|
+
try {
|
|
62
|
+
const tokenParams = {
|
|
63
|
+
client_id: config.clerkClientId,
|
|
64
|
+
refresh_token: tokenData.refresh_token,
|
|
65
|
+
grant_type: 'refresh_token',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (config.clerkClientSecret) {
|
|
69
|
+
tokenParams.client_secret = config.clerkClientSecret;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const response = await fetch(`https://${config.clerkDomain}/oauth/token`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
75
|
+
body: new URLSearchParams(tokenParams),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (response.ok) {
|
|
79
|
+
const newTokenData = await response.json();
|
|
80
|
+
const refreshedToken = newTokenData.id_token || newTokenData.access_token;
|
|
81
|
+
const refreshedDecoded = parseJWT(refreshedToken);
|
|
82
|
+
|
|
83
|
+
sessionId = refreshedDecoded?.sid;
|
|
84
|
+
currentToken = refreshedToken;
|
|
85
|
+
|
|
86
|
+
// Update tokenData with refreshed values
|
|
87
|
+
tokenData.accessToken = newTokenData.access_token;
|
|
88
|
+
tokenData.idToken = newTokenData.id_token;
|
|
89
|
+
tokenData.refresh_token = newTokenData.refresh_token || tokenData.refresh_token;
|
|
90
|
+
tokenData.decoded = refreshedDecoded;
|
|
91
|
+
|
|
92
|
+
if (sessionId) {
|
|
93
|
+
console.error(' ✓ Obtained session ID');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(` Could not refresh token: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Now try to get org-scoped token if we have sessionId
|
|
102
|
+
if (sessionId) {
|
|
103
|
+
try {
|
|
104
|
+
const orgToken = await getOrgScopedToken(
|
|
105
|
+
sessionId,
|
|
106
|
+
tokenData.selectedOrg.id,
|
|
107
|
+
currentToken
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const decoded = parseJWT(orgToken.jwt);
|
|
111
|
+
const updatedToken = {
|
|
112
|
+
...tokenData,
|
|
113
|
+
idToken: orgToken.jwt,
|
|
114
|
+
decoded: decoded,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
saveToken(updatedToken);
|
|
118
|
+
console.error('✓ Token updated with org claims');
|
|
119
|
+
return updatedToken;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`⚠️ Could not get org-scoped token: ${error.message}`);
|
|
122
|
+
// Continue with existing token - API calls may fail
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
console.error('⚠️ Could not obtain session ID for org-scoped token');
|
|
126
|
+
console.error(' Please run: um login');
|
|
72
127
|
}
|
|
73
128
|
}
|
|
74
129
|
|