@lvce-editor/auth-worker 1.15.0 → 1.17.0
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/authWorkerMain.js +101 -161
- package/package.json +1 -1
package/dist/authWorkerMain.js
CHANGED
|
@@ -1184,14 +1184,21 @@ const getString = (value, fallback = '') => {
|
|
|
1184
1184
|
return typeof value === 'string' ? value : fallback;
|
|
1185
1185
|
};
|
|
1186
1186
|
|
|
1187
|
+
const getUserName = value => {
|
|
1188
|
+
if (typeof value.userName === 'string') {
|
|
1189
|
+
return value.userName;
|
|
1190
|
+
}
|
|
1191
|
+
return getString(value.user?.displayName);
|
|
1192
|
+
};
|
|
1187
1193
|
const toBackendAuthState = value => {
|
|
1188
1194
|
return {
|
|
1189
1195
|
authAccessToken: getString(value.accessToken),
|
|
1190
1196
|
authErrorMessage: getString(value.error),
|
|
1191
1197
|
authRefreshToken: getString(value.refreshToken),
|
|
1192
|
-
userName:
|
|
1198
|
+
userName: getUserName(value),
|
|
1193
1199
|
userState: value.accessToken ? 'loggedIn' : 'loggedOut',
|
|
1194
1200
|
userSubscriptionPlan: getString(value.subscriptionPlan),
|
|
1201
|
+
userSubscriptionStatus: getString(value.subscriptionStatus),
|
|
1195
1202
|
userUsedTokens: getNumber(value.usedTokens)
|
|
1196
1203
|
};
|
|
1197
1204
|
};
|
|
@@ -1203,6 +1210,13 @@ const parseBackendAuthResponse = value => {
|
|
|
1203
1210
|
return toBackendAuthState(value);
|
|
1204
1211
|
};
|
|
1205
1212
|
|
|
1213
|
+
const getPayload = async response => {
|
|
1214
|
+
try {
|
|
1215
|
+
return await response.json();
|
|
1216
|
+
} catch {
|
|
1217
|
+
return undefined;
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1206
1220
|
const syncBackendAuth = async backendUrl => {
|
|
1207
1221
|
if (!backendUrl) {
|
|
1208
1222
|
return getLoggedOutBackendAuthState('Backend URL is missing.');
|
|
@@ -1222,12 +1236,7 @@ const syncBackendAuth = async backendUrl => {
|
|
|
1222
1236
|
if (response.status === 401 || response.status === 403) {
|
|
1223
1237
|
return getLoggedOutBackendAuthState();
|
|
1224
1238
|
}
|
|
1225
|
-
|
|
1226
|
-
try {
|
|
1227
|
-
payload = await response.json();
|
|
1228
|
-
} catch {
|
|
1229
|
-
payload = undefined;
|
|
1230
|
-
}
|
|
1239
|
+
const payload = await getPayload(response);
|
|
1231
1240
|
if (!response.ok) {
|
|
1232
1241
|
const parsed = parseBackendAuthResponse(payload);
|
|
1233
1242
|
return getLoggedOutBackendAuthState(parsed.authErrorMessage || 'Backend authentication failed.');
|
|
@@ -1718,16 +1727,6 @@ async function tokenEndpointRequest(as, client, clientAuthentication, grantType,
|
|
|
1718
1727
|
}
|
|
1719
1728
|
const idTokenClaims = new WeakMap();
|
|
1720
1729
|
const jwtRefs = new WeakMap();
|
|
1721
|
-
function getValidatedIdTokenClaims(ref) {
|
|
1722
|
-
if (!ref.id_token) {
|
|
1723
|
-
return undefined;
|
|
1724
|
-
}
|
|
1725
|
-
const claims = idTokenClaims.get(ref);
|
|
1726
|
-
if (!claims) {
|
|
1727
|
-
throw CodedTypeError('"ref" was already garbage collected or did not resolve from the proper sources', ERR_INVALID_ARG_VALUE);
|
|
1728
|
-
}
|
|
1729
|
-
return claims;
|
|
1730
|
-
}
|
|
1731
1730
|
async function processGenericAccessTokenResponse(as, client, response, additionalRequiredIdTokenClaims, decryptFn, recognizedTokenTypes) {
|
|
1732
1731
|
assertAs(as);
|
|
1733
1732
|
assertClient(client);
|
|
@@ -1773,9 +1772,6 @@ async function processGenericAccessTokenResponse(as, client, response, additiona
|
|
|
1773
1772
|
assertNumber(client.default_max_age, true, '"client.default_max_age"');
|
|
1774
1773
|
requiredClaims.push('auth_time');
|
|
1775
1774
|
}
|
|
1776
|
-
if (additionalRequiredIdTokenClaims?.length) {
|
|
1777
|
-
requiredClaims.push(...additionalRequiredIdTokenClaims);
|
|
1778
|
-
}
|
|
1779
1775
|
const {
|
|
1780
1776
|
claims,
|
|
1781
1777
|
jwt
|
|
@@ -1853,27 +1849,6 @@ function validateIssuer(as, result) {
|
|
|
1853
1849
|
return result;
|
|
1854
1850
|
}
|
|
1855
1851
|
const branded = new WeakSet();
|
|
1856
|
-
const nopkce = Symbol();
|
|
1857
|
-
async function authorizationCodeGrantRequest(as, client, clientAuthentication, callbackParameters, redirectUri, codeVerifier, options) {
|
|
1858
|
-
assertAs(as);
|
|
1859
|
-
assertClient(client);
|
|
1860
|
-
if (!branded.has(callbackParameters)) {
|
|
1861
|
-
throw CodedTypeError('"callbackParameters" must be an instance of URLSearchParams obtained from "validateAuthResponse()", or "validateJwtAuthResponse()', ERR_INVALID_ARG_VALUE);
|
|
1862
|
-
}
|
|
1863
|
-
assertString(redirectUri, '"redirectUri"');
|
|
1864
|
-
const code = getURLSearchParameter(callbackParameters, 'code');
|
|
1865
|
-
if (!code) {
|
|
1866
|
-
throw OPE('no authorization code in "callbackParameters"', INVALID_RESPONSE);
|
|
1867
|
-
}
|
|
1868
|
-
const parameters = new URLSearchParams(options?.additionalParameters);
|
|
1869
|
-
parameters.set('redirect_uri', redirectUri);
|
|
1870
|
-
parameters.set('code', code);
|
|
1871
|
-
if (codeVerifier !== nopkce) {
|
|
1872
|
-
assertString(codeVerifier, '"codeVerifier"');
|
|
1873
|
-
parameters.set('code_verifier', codeVerifier);
|
|
1874
|
-
}
|
|
1875
|
-
return tokenEndpointRequest(as, client, clientAuthentication, 'authorization_code', parameters, options);
|
|
1876
|
-
}
|
|
1877
1852
|
const jwtClaimNames = {
|
|
1878
1853
|
aud: 'audience',
|
|
1879
1854
|
c_hash: 'code hash',
|
|
@@ -1901,98 +1876,6 @@ function validatePresence(required, result) {
|
|
|
1901
1876
|
}
|
|
1902
1877
|
return result;
|
|
1903
1878
|
}
|
|
1904
|
-
const expectNoNonce = Symbol();
|
|
1905
|
-
const skipAuthTimeCheck = Symbol();
|
|
1906
|
-
async function processAuthorizationCodeResponse(as, client, response, options) {
|
|
1907
|
-
if (typeof options?.expectedNonce === 'string' || typeof options?.maxAge === 'number' || options?.requireIdToken) {
|
|
1908
|
-
return processAuthorizationCodeOpenIDResponse(as, client, response, options.expectedNonce, options.maxAge, options[jweDecrypt], options.recognizedTokenTypes);
|
|
1909
|
-
}
|
|
1910
|
-
return processAuthorizationCodeOAuth2Response(as, client, response, options?.[jweDecrypt], options?.recognizedTokenTypes);
|
|
1911
|
-
}
|
|
1912
|
-
async function processAuthorizationCodeOpenIDResponse(as, client, response, expectedNonce, maxAge, decryptFn, recognizedTokenTypes) {
|
|
1913
|
-
const additionalRequiredClaims = [];
|
|
1914
|
-
switch (expectedNonce) {
|
|
1915
|
-
case undefined:
|
|
1916
|
-
expectedNonce = expectNoNonce;
|
|
1917
|
-
break;
|
|
1918
|
-
case expectNoNonce:
|
|
1919
|
-
break;
|
|
1920
|
-
default:
|
|
1921
|
-
assertString(expectedNonce, '"expectedNonce" argument');
|
|
1922
|
-
additionalRequiredClaims.push('nonce');
|
|
1923
|
-
}
|
|
1924
|
-
maxAge ??= client.default_max_age;
|
|
1925
|
-
switch (maxAge) {
|
|
1926
|
-
case undefined:
|
|
1927
|
-
maxAge = skipAuthTimeCheck;
|
|
1928
|
-
break;
|
|
1929
|
-
case skipAuthTimeCheck:
|
|
1930
|
-
break;
|
|
1931
|
-
default:
|
|
1932
|
-
assertNumber(maxAge, true, '"maxAge" argument');
|
|
1933
|
-
additionalRequiredClaims.push('auth_time');
|
|
1934
|
-
}
|
|
1935
|
-
const result = await processGenericAccessTokenResponse(as, client, response, additionalRequiredClaims, decryptFn, recognizedTokenTypes);
|
|
1936
|
-
assertString(result.id_token, '"response" body "id_token" property', INVALID_RESPONSE, {
|
|
1937
|
-
body: result
|
|
1938
|
-
});
|
|
1939
|
-
const claims = getValidatedIdTokenClaims(result);
|
|
1940
|
-
if (maxAge !== skipAuthTimeCheck) {
|
|
1941
|
-
const now = epochTime() + getClockSkew(client);
|
|
1942
|
-
const tolerance = getClockTolerance(client);
|
|
1943
|
-
if (claims.auth_time + maxAge < now - tolerance) {
|
|
1944
|
-
throw OPE('too much time has elapsed since the last End-User authentication', JWT_TIMESTAMP_CHECK, {
|
|
1945
|
-
claims,
|
|
1946
|
-
now,
|
|
1947
|
-
tolerance,
|
|
1948
|
-
claim: 'auth_time'
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
if (expectedNonce === expectNoNonce) {
|
|
1953
|
-
if (claims.nonce !== undefined) {
|
|
1954
|
-
throw OPE('unexpected ID Token "nonce" claim value', JWT_CLAIM_COMPARISON, {
|
|
1955
|
-
expected: undefined,
|
|
1956
|
-
claims,
|
|
1957
|
-
claim: 'nonce'
|
|
1958
|
-
});
|
|
1959
|
-
}
|
|
1960
|
-
} else if (claims.nonce !== expectedNonce) {
|
|
1961
|
-
throw OPE('unexpected ID Token "nonce" claim value', JWT_CLAIM_COMPARISON, {
|
|
1962
|
-
expected: expectedNonce,
|
|
1963
|
-
claims,
|
|
1964
|
-
claim: 'nonce'
|
|
1965
|
-
});
|
|
1966
|
-
}
|
|
1967
|
-
return result;
|
|
1968
|
-
}
|
|
1969
|
-
async function processAuthorizationCodeOAuth2Response(as, client, response, decryptFn, recognizedTokenTypes) {
|
|
1970
|
-
const result = await processGenericAccessTokenResponse(as, client, response, undefined, decryptFn, recognizedTokenTypes);
|
|
1971
|
-
const claims = getValidatedIdTokenClaims(result);
|
|
1972
|
-
if (claims) {
|
|
1973
|
-
if (client.default_max_age !== undefined) {
|
|
1974
|
-
assertNumber(client.default_max_age, true, '"client.default_max_age"');
|
|
1975
|
-
const now = epochTime() + getClockSkew(client);
|
|
1976
|
-
const tolerance = getClockTolerance(client);
|
|
1977
|
-
if (claims.auth_time + client.default_max_age < now - tolerance) {
|
|
1978
|
-
throw OPE('too much time has elapsed since the last End-User authentication', JWT_TIMESTAMP_CHECK, {
|
|
1979
|
-
claims,
|
|
1980
|
-
now,
|
|
1981
|
-
tolerance,
|
|
1982
|
-
claim: 'auth_time'
|
|
1983
|
-
});
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
if (claims.nonce !== undefined) {
|
|
1987
|
-
throw OPE('unexpected ID Token "nonce" claim value', JWT_CLAIM_COMPARISON, {
|
|
1988
|
-
expected: undefined,
|
|
1989
|
-
claims,
|
|
1990
|
-
claim: 'nonce'
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
return result;
|
|
1995
|
-
}
|
|
1996
1879
|
const WWW_AUTHENTICATE_CHALLENGE = 'OAUTH_WWW_AUTHENTICATE_CHALLENGE';
|
|
1997
1880
|
const RESPONSE_BODY_ERROR = 'OAUTH_RESPONSE_BODY_ERROR';
|
|
1998
1881
|
const UNSUPPORTED_OPERATION = 'OAUTH_UNSUPPORTED_OPERATION';
|
|
@@ -2006,6 +1889,15 @@ const JWT_TIMESTAMP_CHECK = 'OAUTH_JWT_TIMESTAMP_CHECK_FAILED';
|
|
|
2006
1889
|
const JWT_CLAIM_COMPARISON = 'OAUTH_JWT_CLAIM_COMPARISON_FAILED';
|
|
2007
1890
|
const MISSING_SERVER_METADATA = 'OAUTH_MISSING_SERVER_METADATA';
|
|
2008
1891
|
const INVALID_SERVER_METADATA = 'OAUTH_INVALID_SERVER_METADATA';
|
|
1892
|
+
async function genericTokenEndpointRequest(as, client, clientAuthentication, grantType, parameters, options) {
|
|
1893
|
+
assertAs(as);
|
|
1894
|
+
assertClient(client);
|
|
1895
|
+
assertString(grantType, '"grantType"');
|
|
1896
|
+
return tokenEndpointRequest(as, client, clientAuthentication, grantType, new URLSearchParams(parameters), options);
|
|
1897
|
+
}
|
|
1898
|
+
async function processGenericTokenEndpointResponse(as, client, response, options) {
|
|
1899
|
+
return processGenericAccessTokenResponse(as, client, response, undefined, options?.[jweDecrypt], options?.recognizedTokenTypes);
|
|
1900
|
+
}
|
|
2009
1901
|
function assertReadableResponse(response) {
|
|
2010
1902
|
if (response.bodyUsed) {
|
|
2011
1903
|
throw CodedTypeError('"response" body has been used already', ERR_INVALID_ARG_VALUE);
|
|
@@ -2155,16 +2047,6 @@ function checkSigningAlgorithm(client, issuer, fallback, header) {
|
|
|
2155
2047
|
fallback
|
|
2156
2048
|
});
|
|
2157
2049
|
}
|
|
2158
|
-
function getURLSearchParameter(parameters, name) {
|
|
2159
|
-
const {
|
|
2160
|
-
0: value,
|
|
2161
|
-
length
|
|
2162
|
-
} = parameters.getAll(name);
|
|
2163
|
-
if (length > 1) {
|
|
2164
|
-
throw OPE(`"${name}" parameter must be provided only once`, INVALID_RESPONSE);
|
|
2165
|
-
}
|
|
2166
|
-
return value;
|
|
2167
|
-
}
|
|
2168
2050
|
async function getResponseJsonBody(response, check = assertApplicationJson) {
|
|
2169
2051
|
let json;
|
|
2170
2052
|
try {
|
|
@@ -2507,15 +2389,76 @@ const getLoggedInState = (state, response) => {
|
|
|
2507
2389
|
userName: typeof response.userName === 'string' ? response.userName : state.userName,
|
|
2508
2390
|
userState: accessToken ? 'loggedIn' : 'loggedOut',
|
|
2509
2391
|
userSubscriptionPlan: typeof response.subscriptionPlan === 'string' ? response.subscriptionPlan : state.userSubscriptionPlan,
|
|
2392
|
+
userSubscriptionStatus: typeof response.subscriptionStatus === 'string' ? response.subscriptionStatus : state.userSubscriptionStatus,
|
|
2510
2393
|
userUsedTokens: typeof response.usedTokens === 'number' ? response.usedTokens : state.userUsedTokens
|
|
2511
2394
|
};
|
|
2512
2395
|
};
|
|
2513
2396
|
|
|
2514
2397
|
const isLoginResponse = value => {
|
|
2515
|
-
|
|
2516
|
-
|
|
2398
|
+
return !!value && typeof value === 'object';
|
|
2399
|
+
};
|
|
2400
|
+
|
|
2401
|
+
const databaseName = 'auth-worker';
|
|
2402
|
+
const objectStoreName = 'auth';
|
|
2403
|
+
const memoryStorage = new Map();
|
|
2404
|
+
let databasePromise;
|
|
2405
|
+
|
|
2406
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
2407
|
+
const transactionToPromise = transaction => {
|
|
2408
|
+
return new Promise((resolve, reject) => {
|
|
2409
|
+
transaction.addEventListener('complete', () => {
|
|
2410
|
+
resolve();
|
|
2411
|
+
});
|
|
2412
|
+
transaction.addEventListener('abort', () => {
|
|
2413
|
+
reject(transaction.error ?? new Error('Persistent storage transaction failed.'));
|
|
2414
|
+
});
|
|
2415
|
+
transaction.addEventListener('error', () => {
|
|
2416
|
+
reject(transaction.error ?? new Error('Persistent storage transaction failed.'));
|
|
2417
|
+
});
|
|
2418
|
+
});
|
|
2419
|
+
};
|
|
2420
|
+
const getDatabase = async () => {
|
|
2421
|
+
if (typeof indexedDB === 'undefined') {
|
|
2422
|
+
return undefined;
|
|
2517
2423
|
}
|
|
2518
|
-
|
|
2424
|
+
if (!databasePromise) {
|
|
2425
|
+
databasePromise = new Promise((resolve, reject) => {
|
|
2426
|
+
const request = indexedDB.open(databaseName, 1);
|
|
2427
|
+
request.addEventListener('upgradeneeded', () => {
|
|
2428
|
+
const database = request.result;
|
|
2429
|
+
if (!database.objectStoreNames.contains(objectStoreName)) {
|
|
2430
|
+
database.createObjectStore(objectStoreName);
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
request.addEventListener('success', () => {
|
|
2434
|
+
resolve(request.result);
|
|
2435
|
+
});
|
|
2436
|
+
request.addEventListener('error', () => {
|
|
2437
|
+
reject(request.error ?? new Error('Failed to open persistent auth storage.'));
|
|
2438
|
+
});
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
return databasePromise;
|
|
2442
|
+
};
|
|
2443
|
+
const setPersistentAuthValue = async (key, value) => {
|
|
2444
|
+
memoryStorage.set(key, value);
|
|
2445
|
+
const database = await getDatabase();
|
|
2446
|
+
if (!database) {
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
const transaction = database.transaction(objectStoreName, 'readwrite');
|
|
2450
|
+
const objectStore = transaction.objectStore(objectStoreName);
|
|
2451
|
+
objectStore.put(value, key);
|
|
2452
|
+
await transactionToPromise(transaction);
|
|
2453
|
+
};
|
|
2454
|
+
|
|
2455
|
+
const persistLoginResult = async loginResult => {
|
|
2456
|
+
if (loginResult.userState !== 'loggedIn') {
|
|
2457
|
+
return loginResult;
|
|
2458
|
+
}
|
|
2459
|
+
await setPersistentAuthValue('accessToken', loginResult.authAccessToken ?? '');
|
|
2460
|
+
await setPersistentAuthValue('refreshToken', loginResult.authRefreshToken ?? '');
|
|
2461
|
+
return loginResult;
|
|
2519
2462
|
};
|
|
2520
2463
|
|
|
2521
2464
|
const getBackendOidcTokenUrl = backendUrl => {
|
|
@@ -2534,15 +2477,15 @@ const getClient = () => {
|
|
|
2534
2477
|
client_id: oidcClientId
|
|
2535
2478
|
};
|
|
2536
2479
|
};
|
|
2537
|
-
const exchangeElectronAuthorizationCode = async (backendUrl, code, redirectUri, codeVerifier,
|
|
2480
|
+
const exchangeElectronAuthorizationCode = async (backendUrl, code, redirectUri, codeVerifier, requestTokenEndpoint = genericTokenEndpointRequest, processTokenEndpointResponse = processGenericTokenEndpointResponse) => {
|
|
2538
2481
|
const authorizationServer = getAuthorizationServer(backendUrl);
|
|
2539
2482
|
const client = getClient();
|
|
2540
|
-
const response = await
|
|
2541
|
-
code
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2483
|
+
const response = await requestTokenEndpoint(authorizationServer, client, None(), 'authorization_code', new URLSearchParams({
|
|
2484
|
+
code,
|
|
2485
|
+
code_verifier: codeVerifier,
|
|
2486
|
+
redirect_uri: redirectUri
|
|
2487
|
+
}));
|
|
2488
|
+
const tokenResponse = await processTokenEndpointResponse(authorizationServer, client, response);
|
|
2546
2489
|
return {
|
|
2547
2490
|
accessToken: tokenResponse.access_token,
|
|
2548
2491
|
refreshToken: typeof tokenResponse.refresh_token === 'string' ? tokenResponse.refresh_token : ''
|
|
@@ -2555,12 +2498,12 @@ const hasAuthorizationCode = value => {
|
|
|
2555
2498
|
const getElectronAuthorizationCode = async uid => {
|
|
2556
2499
|
return invoke$2('OAuthServer.getCode', String(uid));
|
|
2557
2500
|
};
|
|
2558
|
-
const waitForElectronBackendLogin = async (backendUrl, uid, redirectUri,
|
|
2501
|
+
const waitForElectronBackendLogin = async (backendUrl, uid, redirectUri, codeVerifier, timeoutMs = 30_000, pollIntervalMs = 1000, getAuthorizationCode = getElectronAuthorizationCode, exchangeAuthorizationCode = exchangeElectronAuthorizationCode) => {
|
|
2559
2502
|
const deadline = Date.now() + timeoutMs;
|
|
2560
2503
|
while (Date.now() < deadline) {
|
|
2561
2504
|
const authorizationCode = await getAuthorizationCode(uid);
|
|
2562
2505
|
if (hasAuthorizationCode(authorizationCode)) {
|
|
2563
|
-
const tokenResponse = await exchangeAuthorizationCode(backendUrl, authorizationCode, redirectUri, codeVerifier
|
|
2506
|
+
const tokenResponse = await exchangeAuthorizationCode(backendUrl, authorizationCode, redirectUri, codeVerifier);
|
|
2564
2507
|
return {
|
|
2565
2508
|
authAccessToken: tokenResponse.accessToken,
|
|
2566
2509
|
authErrorMessage: '',
|
|
@@ -2604,20 +2547,17 @@ const handleClickLogin = async options => {
|
|
|
2604
2547
|
userState: 'loggedOut'
|
|
2605
2548
|
};
|
|
2606
2549
|
}
|
|
2607
|
-
return getLoggedInState(signingInState, response);
|
|
2550
|
+
return persistLoginResult(getLoggedInState(signingInState, response));
|
|
2608
2551
|
}
|
|
2609
2552
|
const uid = 0;
|
|
2610
2553
|
const {
|
|
2611
2554
|
codeVerifier,
|
|
2612
2555
|
loginUrl,
|
|
2613
|
-
nonce,
|
|
2614
2556
|
redirectUri
|
|
2615
2557
|
} = await getBackendLoginRequest(backendUrl, platform, uid);
|
|
2616
2558
|
await invoke$1('Open.openUrl', loginUrl, platform, authUseRedirect);
|
|
2617
|
-
const authState = platform === Electron ? await waitForElectronBackendLogin(backendUrl, uid, redirectUri,
|
|
2618
|
-
return
|
|
2619
|
-
...authState
|
|
2620
|
-
};
|
|
2559
|
+
const authState = platform === Electron ? await waitForElectronBackendLogin(backendUrl, uid, redirectUri, codeVerifier) : await waitForBackendLogin(backendUrl);
|
|
2560
|
+
return persistLoginResult(authState);
|
|
2621
2561
|
} catch (error) {
|
|
2622
2562
|
const errorMessage = error instanceof Error && error.message ? error.message : 'Backend authentication failed.';
|
|
2623
2563
|
return {
|