@metamask-previews/seedless-onboarding-controller 2.0.1-preview-2bb8758e → 2.0.1-preview-c10fdda1
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 +6 -0
- package/dist/SeedlessOnboardingController.cjs +120 -17
- package/dist/SeedlessOnboardingController.cjs.map +1 -1
- package/dist/SeedlessOnboardingController.d.cts +19 -3
- package/dist/SeedlessOnboardingController.d.cts.map +1 -1
- package/dist/SeedlessOnboardingController.d.mts +19 -3
- package/dist/SeedlessOnboardingController.d.mts.map +1 -1
- package/dist/SeedlessOnboardingController.mjs +120 -17
- package/dist/SeedlessOnboardingController.mjs.map +1 -1
- package/dist/constants.cjs +2 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +2 -0
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +2 -0
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +2 -0
- package/dist/constants.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +38 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +38 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `access_token` and `metadata_access_token` in seedless controller state. ([#6060](https://github.com/MetaMask/core/pull/6060))
|
|
13
|
+
- `access_token` can be used by profile sync pairing and for other apis access after wallet is unlocked.
|
|
14
|
+
- `metadata_access_token` is used to give access for web3auth metadata apis.
|
|
15
|
+
|
|
10
16
|
## [2.0.1]
|
|
11
17
|
|
|
12
18
|
### Fixed
|
|
@@ -102,6 +102,17 @@ const seedlessOnboardingMetadata = {
|
|
|
102
102
|
persist: false,
|
|
103
103
|
anonymous: true,
|
|
104
104
|
},
|
|
105
|
+
// stays in vault
|
|
106
|
+
accessToken: {
|
|
107
|
+
persist: false,
|
|
108
|
+
anonymous: true,
|
|
109
|
+
},
|
|
110
|
+
// stays outside of vault as this token is accessed by the metadata service
|
|
111
|
+
// before the vault is created or unlocked.
|
|
112
|
+
metadataAccessToken: {
|
|
113
|
+
persist: true,
|
|
114
|
+
anonymous: true,
|
|
115
|
+
},
|
|
105
116
|
encryptedSeedlessEncryptionKey: {
|
|
106
117
|
persist: true,
|
|
107
118
|
anonymous: true,
|
|
@@ -150,6 +161,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
150
161
|
this.toprfClient = new toprf_secure_backup_1.ToprfSecureBackup({
|
|
151
162
|
network,
|
|
152
163
|
keyDeriver: toprfKeyDeriver,
|
|
164
|
+
fetchMetadataAccessCreds: this.fetchMetadataAccessCreds.bind(this),
|
|
153
165
|
});
|
|
154
166
|
__classPrivateFieldSet(this, _SeedlessOnboardingController_refreshJWTToken, refreshJWTToken, "f");
|
|
155
167
|
__classPrivateFieldSet(this, _SeedlessOnboardingController_revokeRefreshToken, revokeRefreshToken, "f");
|
|
@@ -162,6 +174,25 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
162
174
|
__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_setUnlocked).call(this);
|
|
163
175
|
});
|
|
164
176
|
}
|
|
177
|
+
async fetchMetadataAccessCreds() {
|
|
178
|
+
const { metadataAccessToken } = this.state;
|
|
179
|
+
if (!metadataAccessToken) {
|
|
180
|
+
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidMetadataAccessToken);
|
|
181
|
+
}
|
|
182
|
+
// Check if token is expired and refresh if needed
|
|
183
|
+
const decodedToken = this.decodeJWTToken(metadataAccessToken);
|
|
184
|
+
if (decodedToken.exp < Math.floor(Date.now() / 1000)) {
|
|
185
|
+
// Token is expired, refresh it
|
|
186
|
+
await this.refreshAuthTokens();
|
|
187
|
+
// Get the new token after refresh
|
|
188
|
+
const { metadataAccessToken: newMetadataAccessToken } = this.state;
|
|
189
|
+
if (!newMetadataAccessToken) {
|
|
190
|
+
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidMetadataAccessToken);
|
|
191
|
+
}
|
|
192
|
+
return { metadataAccessToken: newMetadataAccessToken };
|
|
193
|
+
}
|
|
194
|
+
return { metadataAccessToken };
|
|
195
|
+
}
|
|
165
196
|
/**
|
|
166
197
|
* Authenticate OAuth user using the seedless onboarding flow
|
|
167
198
|
* and determine if the user is already registered or not.
|
|
@@ -175,13 +206,15 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
175
206
|
* @param params.socialLoginEmail - The user email from Social login.
|
|
176
207
|
* @param params.refreshToken - refresh token for refreshing expired nodeAuthTokens.
|
|
177
208
|
* @param params.revokeToken - revoke token for revoking refresh token and get new refresh token and new revoke token.
|
|
209
|
+
* @param params.accessToken - Access token for pairing with profile sync auth service and to access other services.
|
|
210
|
+
* @param params.metadataAccessToken - Metadata access token for accessing the metadata service before the vault is created or unlocked.
|
|
178
211
|
* @param params.skipLock - Optional flag to skip acquiring the controller lock. (to prevent deadlock in case the caller already acquired the lock)
|
|
179
212
|
* @returns A promise that resolves to the authentication result.
|
|
180
213
|
*/
|
|
181
214
|
async authenticate(params) {
|
|
182
215
|
const doAuthenticateWithNodes = async () => {
|
|
183
216
|
try {
|
|
184
|
-
const { idTokens, authConnectionId, groupedAuthConnectionId, userId, authConnection, socialLoginEmail, refreshToken, revokeToken, } = params;
|
|
217
|
+
const { idTokens, authConnectionId, groupedAuthConnectionId, userId, authConnection, socialLoginEmail, refreshToken, revokeToken, accessToken, metadataAccessToken, } = params;
|
|
185
218
|
const authenticationResult = await this.toprfClient.authenticate({
|
|
186
219
|
authConnectionId,
|
|
187
220
|
userId,
|
|
@@ -203,6 +236,12 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
203
236
|
// Temporarily store revoke token in state for later vault creation
|
|
204
237
|
state.revokeToken = revokeToken;
|
|
205
238
|
}
|
|
239
|
+
if (accessToken) {
|
|
240
|
+
state.accessToken = accessToken;
|
|
241
|
+
}
|
|
242
|
+
if (metadataAccessToken) {
|
|
243
|
+
state.metadataAccessToken = metadataAccessToken;
|
|
244
|
+
}
|
|
206
245
|
});
|
|
207
246
|
return authenticationResult;
|
|
208
247
|
}
|
|
@@ -461,6 +500,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
461
500
|
delete state.vaultEncryptionKey;
|
|
462
501
|
delete state.vaultEncryptionSalt;
|
|
463
502
|
delete state.revokeToken;
|
|
503
|
+
delete state.accessToken;
|
|
464
504
|
});
|
|
465
505
|
__classPrivateFieldSet(this, _SeedlessOnboardingController_isUnlocked, false, "f");
|
|
466
506
|
}
|
|
@@ -582,14 +622,14 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
582
622
|
return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_loadKeyringEncryptionKey).call(this, encKey);
|
|
583
623
|
}
|
|
584
624
|
/**
|
|
585
|
-
* Refresh expired nodeAuthTokens using the stored refresh token.
|
|
625
|
+
* Refresh expired nodeAuthTokens, accessToken, and metadataAccessToken using the stored refresh token.
|
|
586
626
|
*
|
|
587
627
|
* This method retrieves the refresh token from the vault and uses it to obtain
|
|
588
628
|
* new nodeAuthTokens when the current ones have expired.
|
|
589
629
|
*
|
|
590
630
|
* @returns A promise that resolves to the new nodeAuthTokens.
|
|
591
631
|
*/
|
|
592
|
-
async
|
|
632
|
+
async refreshAuthTokens() {
|
|
593
633
|
__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
|
|
594
634
|
const { refreshToken } = this.state;
|
|
595
635
|
try {
|
|
@@ -597,10 +637,12 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
597
637
|
connection: this.state.authConnection,
|
|
598
638
|
refreshToken,
|
|
599
639
|
});
|
|
600
|
-
const { idTokens } = res;
|
|
640
|
+
const { idTokens, accessToken, metadataAccessToken } = res;
|
|
601
641
|
// re-authenticate with the new id tokens to set new node auth tokens
|
|
602
642
|
await this.authenticate({
|
|
603
643
|
idTokens,
|
|
644
|
+
accessToken,
|
|
645
|
+
metadataAccessToken,
|
|
604
646
|
authConnection: this.state.authConnection,
|
|
605
647
|
authConnectionId: this.state.authConnectionId,
|
|
606
648
|
groupedAuthConnectionId: this.state.groupedAuthConnectionId,
|
|
@@ -656,6 +698,34 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
656
698
|
// check if the token is expired
|
|
657
699
|
return decodedToken.exp < Date.now() / 1000;
|
|
658
700
|
}
|
|
701
|
+
checkMetadataAccessTokenExpired() {
|
|
702
|
+
try {
|
|
703
|
+
__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
|
|
704
|
+
const { metadataAccessToken } = this.state;
|
|
705
|
+
if (!metadataAccessToken) {
|
|
706
|
+
return true; // Consider missing token as expired
|
|
707
|
+
}
|
|
708
|
+
const decodedToken = this.decodeJWTToken(metadataAccessToken);
|
|
709
|
+
return decodedToken.exp < Math.floor(Date.now() / 1000);
|
|
710
|
+
}
|
|
711
|
+
catch {
|
|
712
|
+
return true; // Consider unauthenticated user as having expired tokens
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
checkAccessTokenExpired() {
|
|
716
|
+
try {
|
|
717
|
+
__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
|
|
718
|
+
const { accessToken } = this.state;
|
|
719
|
+
if (!accessToken) {
|
|
720
|
+
return true; // Consider missing token as expired
|
|
721
|
+
}
|
|
722
|
+
const decodedToken = this.decodeJWTToken(accessToken);
|
|
723
|
+
return decodedToken.exp < Math.floor(Date.now() / 1000);
|
|
724
|
+
}
|
|
725
|
+
catch {
|
|
726
|
+
return true; // Consider unauthenticated user as having expired tokens
|
|
727
|
+
}
|
|
728
|
+
}
|
|
659
729
|
/**
|
|
660
730
|
* Decode the node auth token from base64 to json object.
|
|
661
731
|
*
|
|
@@ -665,6 +735,30 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
|
|
|
665
735
|
decodeNodeAuthToken(token) {
|
|
666
736
|
return JSON.parse((0, utils_2.bytesToUtf8)((0, utils_1.base64ToBytes)(token)));
|
|
667
737
|
}
|
|
738
|
+
/**
|
|
739
|
+
* Decode JWT token
|
|
740
|
+
*
|
|
741
|
+
* @param token - The JWT token to decode.
|
|
742
|
+
* @returns The decoded JWT token.
|
|
743
|
+
*/
|
|
744
|
+
decodeJWTToken(token) {
|
|
745
|
+
// JWT tokens have 3 parts separated by dots: header.payload.signature
|
|
746
|
+
const parts = token.split('.');
|
|
747
|
+
if (parts.length !== 3) {
|
|
748
|
+
throw new Error('Invalid JWT token format');
|
|
749
|
+
}
|
|
750
|
+
// Decode the payload (second part)
|
|
751
|
+
const payload = parts[1];
|
|
752
|
+
// Add padding if needed for base64 decoding
|
|
753
|
+
const paddedPayload = payload + '='.repeat((4 - (payload.length % 4)) % 4);
|
|
754
|
+
try {
|
|
755
|
+
const decoded = JSON.parse(Buffer.from(paddedPayload, 'base64').toString());
|
|
756
|
+
return decoded;
|
|
757
|
+
}
|
|
758
|
+
catch (error) {
|
|
759
|
+
throw new Error(`Failed to decode JWT token: ${error instanceof Error ? error.message : String(error)}`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
668
762
|
}
|
|
669
763
|
exports.SeedlessOnboardingController = SeedlessOnboardingController;
|
|
670
764
|
_SeedlessOnboardingController_vaultEncryptor = new WeakMap(), _SeedlessOnboardingController_controllerOperationMutex = new WeakMap(), _SeedlessOnboardingController_vaultOperationMutex = new WeakMap(), _SeedlessOnboardingController_refreshJWTToken = new WeakMap(), _SeedlessOnboardingController_revokeRefreshToken = new WeakMap(), _SeedlessOnboardingController_isUnlocked = new WeakMap(), _SeedlessOnboardingController_instances = new WeakSet(), _SeedlessOnboardingController_submitGlobalPassword =
|
|
@@ -919,7 +1013,6 @@ async function _SeedlessOnboardingController_encryptAndStoreSecretData(params) {
|
|
|
919
1013
|
* @param password - The optional password to unlock the vault.
|
|
920
1014
|
* @param encryptionKey - The optional encryption key to unlock the vault.
|
|
921
1015
|
* @returns A promise that resolves to an object containing:
|
|
922
|
-
* - nodeAuthTokens: Authentication tokens to communicate with the TOPRF service
|
|
923
1016
|
* - toprfEncryptionKey: The decrypted TOPRF encryption key
|
|
924
1017
|
* - toprfAuthKeyPair: The decrypted TOPRF authentication key pair
|
|
925
1018
|
* @throws {Error} If:
|
|
@@ -962,20 +1055,19 @@ async function _SeedlessOnboardingController_unlockVaultAndGetBackupEncKey(passw
|
|
|
962
1055
|
updatedState.vaultEncryptionKey = vaultEncryptionKey;
|
|
963
1056
|
updatedState.vaultEncryptionSalt = vaultEncryptionSalt;
|
|
964
1057
|
}
|
|
965
|
-
const {
|
|
966
|
-
// update the state with the restored nodeAuthTokens
|
|
1058
|
+
const { toprfEncryptionKey, toprfPwEncryptionKey, toprfAuthKeyPair, revokeToken, accessToken, } = __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_parseVaultData).call(this, decryptedVaultData);
|
|
967
1059
|
this.update((state) => {
|
|
968
|
-
state.nodeAuthTokens = nodeAuthTokens;
|
|
969
1060
|
state.vaultEncryptionKey = updatedState.vaultEncryptionKey;
|
|
970
1061
|
state.vaultEncryptionSalt = updatedState.vaultEncryptionSalt;
|
|
971
1062
|
state.revokeToken = revokeToken;
|
|
1063
|
+
state.accessToken = accessToken;
|
|
972
1064
|
});
|
|
973
1065
|
return {
|
|
974
|
-
nodeAuthTokens,
|
|
975
1066
|
toprfEncryptionKey,
|
|
976
1067
|
toprfPwEncryptionKey,
|
|
977
1068
|
toprfAuthKeyPair,
|
|
978
1069
|
revokeToken,
|
|
1070
|
+
accessToken,
|
|
979
1071
|
};
|
|
980
1072
|
});
|
|
981
1073
|
}, _SeedlessOnboardingController_withPersistedSecretMetadataBackupsState =
|
|
@@ -1051,14 +1143,17 @@ async function _SeedlessOnboardingController_createNewVaultWithAuthData({ passwo
|
|
|
1051
1143
|
if (!this.state.revokeToken) {
|
|
1052
1144
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidRevokeToken);
|
|
1053
1145
|
}
|
|
1146
|
+
if (!this.state.accessToken) {
|
|
1147
|
+
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidAccessToken);
|
|
1148
|
+
}
|
|
1054
1149
|
__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_setUnlocked).call(this);
|
|
1055
1150
|
const { toprfEncryptionKey, toprfPwEncryptionKey, toprfAuthKeyPair } = __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_serializeKeyData).call(this, rawToprfEncryptionKey, rawToprfPwEncryptionKey, rawToprfAuthKeyPair);
|
|
1056
1151
|
const serializedVaultData = JSON.stringify({
|
|
1057
|
-
authTokens: this.state.nodeAuthTokens,
|
|
1058
1152
|
toprfEncryptionKey,
|
|
1059
1153
|
toprfPwEncryptionKey,
|
|
1060
1154
|
toprfAuthKeyPair,
|
|
1061
1155
|
revokeToken: this.state.revokeToken,
|
|
1156
|
+
accessToken: this.state.accessToken,
|
|
1062
1157
|
});
|
|
1063
1158
|
await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_updateVault).call(this, {
|
|
1064
1159
|
password,
|
|
@@ -1157,11 +1252,11 @@ async function _SeedlessOnboardingController_withVaultLock(callback) {
|
|
|
1157
1252
|
pk: (0, utils_1.base64ToBytes)(parsedToprfAuthKeyPair.pk),
|
|
1158
1253
|
};
|
|
1159
1254
|
return {
|
|
1160
|
-
nodeAuthTokens: parsedVaultData.authTokens,
|
|
1161
1255
|
toprfEncryptionKey: rawToprfEncryptionKey,
|
|
1162
1256
|
toprfPwEncryptionKey: rawToprfPwEncryptionKey,
|
|
1163
1257
|
toprfAuthKeyPair: rawToprfAuthKeyPair,
|
|
1164
1258
|
revokeToken: parsedVaultData.revokeToken,
|
|
1259
|
+
accessToken: parsedVaultData.accessToken,
|
|
1165
1260
|
};
|
|
1166
1261
|
}, _SeedlessOnboardingController_assertIsUnlocked = function _SeedlessOnboardingController_assertIsUnlocked() {
|
|
1167
1262
|
if (!__classPrivateFieldGet(this, _SeedlessOnboardingController_isUnlocked, "f")) {
|
|
@@ -1186,6 +1281,10 @@ async function _SeedlessOnboardingController_withVaultLock(callback) {
|
|
|
1186
1281
|
if (!('refreshToken' in value) || typeof value.refreshToken !== 'string') {
|
|
1187
1282
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidRefreshToken);
|
|
1188
1283
|
}
|
|
1284
|
+
if (!('metadataAccessToken' in value) ||
|
|
1285
|
+
typeof value.metadataAccessToken !== 'string') {
|
|
1286
|
+
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidMetadataAccessToken);
|
|
1287
|
+
}
|
|
1189
1288
|
}, _SeedlessOnboardingController_assertIsSRPBackedUpUser = function _SeedlessOnboardingController_assertIsSRPBackedUpUser(value) {
|
|
1190
1289
|
if (!this.state.authPubKey) {
|
|
1191
1290
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.SRPNotBackedUpError);
|
|
@@ -1212,8 +1311,6 @@ async function _SeedlessOnboardingController_assertPasswordInSync(options) {
|
|
|
1212
1311
|
// value is not valid vault data if any of the following conditions are true:
|
|
1213
1312
|
if (!value || // value is not defined
|
|
1214
1313
|
typeof value !== 'object' || // value is not an object
|
|
1215
|
-
!('authTokens' in value) || // authTokens is not defined
|
|
1216
|
-
typeof value.authTokens !== 'object' || // authTokens is not an object
|
|
1217
1314
|
!('toprfEncryptionKey' in value) || // toprfEncryptionKey is not defined
|
|
1218
1315
|
typeof value.toprfEncryptionKey !== 'string' || // toprfEncryptionKey is not a string
|
|
1219
1316
|
!('toprfPwEncryptionKey' in value) || // toprfPwEncryptionKey is not defined
|
|
@@ -1221,7 +1318,9 @@ async function _SeedlessOnboardingController_assertPasswordInSync(options) {
|
|
|
1221
1318
|
!('toprfAuthKeyPair' in value) || // toprfAuthKeyPair is not defined
|
|
1222
1319
|
typeof value.toprfAuthKeyPair !== 'string' || // toprfAuthKeyPair is not a string
|
|
1223
1320
|
!('revokeToken' in value) || // revokeToken is not defined
|
|
1224
|
-
typeof value.revokeToken !== 'string' // revokeToken is not a string
|
|
1321
|
+
typeof value.revokeToken !== 'string' || // revokeToken is not a string
|
|
1322
|
+
!('accessToken' in value) || // accessToken is not defined
|
|
1323
|
+
typeof value.accessToken !== 'string' // accessToken is not a string
|
|
1225
1324
|
) {
|
|
1226
1325
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.VaultDataError);
|
|
1227
1326
|
}
|
|
@@ -1248,9 +1347,13 @@ async function _SeedlessOnboardingController_executeWithTokenRefresh(operation,
|
|
|
1248
1347
|
try {
|
|
1249
1348
|
// proactively check for expired tokens and refresh them if needed
|
|
1250
1349
|
const isNodeAuthTokenExpired = this.checkNodeAuthTokenExpired();
|
|
1251
|
-
|
|
1350
|
+
const isMetadataAccessTokenExpired = this.checkMetadataAccessTokenExpired();
|
|
1351
|
+
const isAccessTokenExpired = this.checkAccessTokenExpired();
|
|
1352
|
+
if (isNodeAuthTokenExpired ||
|
|
1353
|
+
isMetadataAccessTokenExpired ||
|
|
1354
|
+
isAccessTokenExpired) {
|
|
1252
1355
|
log(`JWT token expired during ${operationName}, attempting to refresh tokens`, 'node auth token exp check');
|
|
1253
|
-
await this.
|
|
1356
|
+
await this.refreshAuthTokens();
|
|
1254
1357
|
}
|
|
1255
1358
|
return await operation();
|
|
1256
1359
|
}
|
|
@@ -1260,7 +1363,7 @@ async function _SeedlessOnboardingController_executeWithTokenRefresh(operation,
|
|
|
1260
1363
|
log(`Token expired during ${operationName}, attempting to refresh tokens`, error);
|
|
1261
1364
|
try {
|
|
1262
1365
|
// Refresh the tokens
|
|
1263
|
-
await this.
|
|
1366
|
+
await this.refreshAuthTokens();
|
|
1264
1367
|
// Retry the operation with fresh tokens
|
|
1265
1368
|
return await operation();
|
|
1266
1369
|
}
|