@supabase/gotrue-js 2.108.2 → 2.112.3
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/README.md +6 -2
- package/dist/main/GoTrueAdminApi.d.ts +1 -4
- package/dist/main/GoTrueAdminApi.d.ts.map +1 -1
- package/dist/main/GoTrueAdminApi.js +1 -4
- package/dist/main/GoTrueAdminApi.js.map +1 -1
- package/dist/main/GoTrueClient.d.ts +67 -21
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +217 -68
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/constants.d.ts +13 -0
- package/dist/main/lib/constants.d.ts.map +1 -1
- package/dist/main/lib/constants.js +14 -1
- package/dist/main/lib/constants.js.map +1 -1
- package/dist/main/lib/errors.d.ts +1 -1
- package/dist/main/lib/fetch.d.ts.map +1 -1
- package/dist/main/lib/fetch.js +12 -6
- package/dist/main/lib/fetch.js.map +1 -1
- package/dist/main/lib/helpers.d.ts +50 -1
- package/dist/main/lib/helpers.d.ts.map +1 -1
- package/dist/main/lib/helpers.js +161 -5
- package/dist/main/lib/helpers.js.map +1 -1
- package/dist/main/lib/locks.d.ts +1 -1
- package/dist/main/lib/locks.js +1 -1
- package/dist/main/lib/types.d.ts +71 -9
- package/dist/main/lib/types.d.ts.map +1 -1
- package/dist/main/lib/types.js.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/module/GoTrueAdminApi.d.ts +1 -4
- package/dist/module/GoTrueAdminApi.d.ts.map +1 -1
- package/dist/module/GoTrueAdminApi.js +1 -4
- package/dist/module/GoTrueAdminApi.js.map +1 -1
- package/dist/module/GoTrueClient.d.ts +67 -21
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +219 -70
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/constants.d.ts +13 -0
- package/dist/module/lib/constants.d.ts.map +1 -1
- package/dist/module/lib/constants.js +13 -0
- package/dist/module/lib/constants.js.map +1 -1
- package/dist/module/lib/errors.d.ts +1 -1
- package/dist/module/lib/fetch.d.ts.map +1 -1
- package/dist/module/lib/fetch.js +12 -6
- package/dist/module/lib/fetch.js.map +1 -1
- package/dist/module/lib/helpers.d.ts +50 -1
- package/dist/module/lib/helpers.d.ts.map +1 -1
- package/dist/module/lib/helpers.js +153 -5
- package/dist/module/lib/helpers.js.map +1 -1
- package/dist/module/lib/locks.d.ts +1 -1
- package/dist/module/lib/locks.js +1 -1
- package/dist/module/lib/types.d.ts +71 -9
- package/dist/module/lib/types.d.ts.map +1 -1
- package/dist/module/lib/types.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/dist/tsconfig.module.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/GoTrueAdminApi.ts +1 -4
- package/src/GoTrueClient.ts +268 -91
- package/src/lib/constants.ts +15 -0
- package/src/lib/errors.ts +1 -1
- package/src/lib/fetch.ts +13 -8
- package/src/lib/helpers.ts +198 -6
- package/src/lib/locks.ts +1 -1
- package/src/lib/types.ts +71 -9
- package/src/lib/version.ts +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import GoTrueAdminApi from './GoTrueAdminApi';
|
|
2
|
-
import { AUTO_REFRESH_TICK_DURATION_MS, AUTO_REFRESH_TICK_THRESHOLD, DEFAULT_HEADERS, EXPIRY_MARGIN_MS, GOTRUE_URL, JWKS_TTL, REFRESH_FAILURE_COOLDOWN_MS, STORAGE_KEY, } from './lib/constants';
|
|
2
|
+
import { AUTO_REFRESH_TICK_DURATION_MS, AUTO_REFRESH_TICK_THRESHOLD, DEFAULT_HEADERS, EXPIRY_MARGIN_MS, GOTRUE_URL, JWKS_TTL, PKCE_FLOW_ID_PARAM, REFRESH_FAILURE_COOLDOWN_MS, STORAGE_KEY, } from './lib/constants';
|
|
3
3
|
import { AuthImplicitGrantRedirectError, AuthInvalidCredentialsError, AuthInvalidJwtError, AuthInvalidTokenResponseError, AuthPKCECodeVerifierMissingError, AuthPKCEGrantCodeExchangeError, AuthRefreshDiscardedError, AuthSessionMissingError, AuthUnknownError, isAuthApiError, isAuthError, isAuthImplicitGrantRedirectError, isAuthRefreshDiscardedError, isAuthRetryableFetchError, isAuthSessionMissingError, } from './lib/errors';
|
|
4
4
|
import { _request, _sessionResponse, _sessionResponsePassword, _ssoResponse, _userResponse, } from './lib/fetch';
|
|
5
|
-
import { assertPasskeyExperimentalEnabled, decodeJWT, deepClone, Deferred, generateCallbackId, getAlgorithm, getCodeChallengeAndMethod, getItemAsync, insecureUserWarningProxy, isBrowser, parseParametersFromURL, removeItemAsync, resolveFetch, retryable, setItemAsync, sleep, supportsLocalStorage, userNotAvailableProxy, validateExp, } from './lib/helpers';
|
|
5
|
+
import { appendFlowIdToRedirectTo, assertPasskeyExperimentalEnabled, decodeJWT, deepClone, Deferred, generateCallbackId, getAlgorithm, getCodeChallengeAndMethod, getItemAsync, insecureUserWarningProxy, isBrowser, parseParametersFromURL, pkceVerifierSlotKey, removeAllPKCEVerifiers, removeItemAsync, removePKCEVerifier, resolveFetch, retrievePKCEVerifier, retryable, setItemAsync, sleep, supportsLocalStorage, userNotAvailableProxy, validateExp, validatePKCEFlowId, } from './lib/helpers';
|
|
6
6
|
import { memoryLocalStorageAdapter } from './lib/local-storage';
|
|
7
7
|
import { LockAcquireTimeoutError } from './lib/locks';
|
|
8
8
|
import { polyfillGlobalThis } from './lib/polyfills';
|
|
@@ -126,6 +126,19 @@ class GoTrueClient {
|
|
|
126
126
|
* Keep extra care to never reject or throw uncaught errors
|
|
127
127
|
*/
|
|
128
128
|
this.initializePromise = null;
|
|
129
|
+
/**
|
|
130
|
+
* Non-null only while `initialize()` is running. While open,
|
|
131
|
+
* `_notifyAllSubscribers` enqueues init-chain notifications (those fired with
|
|
132
|
+
* `broadcast = true`, i.e. from `_recoverAndRefresh`) into this array instead
|
|
133
|
+
* of firing directly, so that `initializePromise` is guaranteed to be
|
|
134
|
+
* resolved before any subscriber callback runs. Callbacks that call
|
|
135
|
+
* `getSession()` / `getUser()` etc. would otherwise deadlock because those
|
|
136
|
+
* methods await `initializePromise`. Notifications from the incoming
|
|
137
|
+
* BroadcastChannel handler (`broadcast = false`) are not enqueued — they fire
|
|
138
|
+
* immediately. Flushed (in order) by `initialize()` after `initializePromise`
|
|
139
|
+
* settles.
|
|
140
|
+
*/
|
|
141
|
+
this._pendingInitNotifications = null;
|
|
129
142
|
this.detectSessionInUrl = true;
|
|
130
143
|
this.hasCustomAuthorizationHeader = false;
|
|
131
144
|
this.suppressGetSessionWarning = false;
|
|
@@ -315,9 +328,19 @@ class GoTrueClient {
|
|
|
315
328
|
* @category Auth
|
|
316
329
|
*/
|
|
317
330
|
async initialize() {
|
|
331
|
+
var _a;
|
|
318
332
|
if (this.initializePromise) {
|
|
319
333
|
return await this.initializePromise;
|
|
320
334
|
}
|
|
335
|
+
// Open the notification queue before _initialize() runs so that every
|
|
336
|
+
// _notifyAllSubscribers call inside the init chain enqueues instead of
|
|
337
|
+
// firing. Without this, a callback receiving SIGNED_IN (or TOKEN_REFRESHED
|
|
338
|
+
// / SIGNED_OUT) during _recoverAndRefresh would deadlock if it called
|
|
339
|
+
// getSession() / getUser() — those methods await initializePromise, which
|
|
340
|
+
// can only resolve after the callback returns, which can only return after
|
|
341
|
+
// getSession() resolves. The queue is flushed below after initializePromise
|
|
342
|
+
// has settled, so callbacks run with a fully resolved initializePromise.
|
|
343
|
+
this._pendingInitNotifications = [];
|
|
321
344
|
this.initializePromise = (async () => {
|
|
322
345
|
if (this.lock != null) {
|
|
323
346
|
// TODO(v3): remove legacy lock path
|
|
@@ -327,7 +350,15 @@ class GoTrueClient {
|
|
|
327
350
|
}
|
|
328
351
|
return await this._initialize();
|
|
329
352
|
})();
|
|
330
|
-
|
|
353
|
+
const result = await this.initializePromise;
|
|
354
|
+
// initializePromise is now resolved — flush queued notifications in order.
|
|
355
|
+
// Callbacks can safely call getSession() / getUser() / signOut() etc.
|
|
356
|
+
const queue = (_a = this._pendingInitNotifications) !== null && _a !== void 0 ? _a : [];
|
|
357
|
+
this._pendingInitNotifications = null;
|
|
358
|
+
for (const n of queue) {
|
|
359
|
+
await this._notifyAllSubscribers(n.event, n.session, n.broadcast);
|
|
360
|
+
}
|
|
361
|
+
return result;
|
|
331
362
|
}
|
|
332
363
|
/**
|
|
333
364
|
* IMPORTANT:
|
|
@@ -683,6 +714,7 @@ class GoTrueClient {
|
|
|
683
714
|
*/
|
|
684
715
|
async signUp(credentials) {
|
|
685
716
|
var _a, _b, _c;
|
|
717
|
+
let flowId = null;
|
|
686
718
|
try {
|
|
687
719
|
let res;
|
|
688
720
|
if ('email' in credentials) {
|
|
@@ -691,11 +723,11 @@ class GoTrueClient {
|
|
|
691
723
|
let codeChallengeMethod = null;
|
|
692
724
|
if (this.flowType === 'pkce') {
|
|
693
725
|
;
|
|
694
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
726
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
695
727
|
}
|
|
696
728
|
res = await _request(this.fetch, 'POST', `${this.url}/signup`, {
|
|
697
729
|
headers: this.headers,
|
|
698
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
730
|
+
redirectTo: this._maybeAppendFlowIdToRedirect(options === null || options === void 0 ? void 0 : options.emailRedirectTo, flowId),
|
|
699
731
|
body: {
|
|
700
732
|
email,
|
|
701
733
|
password,
|
|
@@ -726,7 +758,7 @@ class GoTrueClient {
|
|
|
726
758
|
}
|
|
727
759
|
const { data, error } = res;
|
|
728
760
|
if (error || !data) {
|
|
729
|
-
await
|
|
761
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
730
762
|
return this._returnResult({ data: { user: null, session: null }, error: error });
|
|
731
763
|
}
|
|
732
764
|
const session = data.session;
|
|
@@ -738,7 +770,7 @@ class GoTrueClient {
|
|
|
738
770
|
return this._returnResult({ data: { user, session }, error: null });
|
|
739
771
|
}
|
|
740
772
|
catch (error) {
|
|
741
|
-
await
|
|
773
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
742
774
|
if (isAuthError(error)) {
|
|
743
775
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
744
776
|
}
|
|
@@ -953,7 +985,8 @@ class GoTrueClient {
|
|
|
953
985
|
* {
|
|
954
986
|
* data: {
|
|
955
987
|
* provider: 'github',
|
|
956
|
-
* url: <PROVIDER_URL_TO_REDIRECT_TO
|
|
988
|
+
* url: <PROVIDER_URL_TO_REDIRECT_TO>,
|
|
989
|
+
* flowId: <PKCE_FLOW_ID_OR_NULL>
|
|
957
990
|
* },
|
|
958
991
|
* error: null
|
|
959
992
|
* }
|
|
@@ -1026,12 +1059,29 @@ class GoTrueClient {
|
|
|
1026
1059
|
*
|
|
1027
1060
|
* @remarks
|
|
1028
1061
|
* - Used when `flowType` is set to `pkce` in client options.
|
|
1062
|
+
* - When several PKCE flows are in flight at once, pass `options.flowId` so
|
|
1063
|
+
* the code is exchanged with the verifier created by that specific flow.
|
|
1064
|
+
* The flow id is returned by `signInWithOAuth`, and with
|
|
1065
|
+
* `experimental.appendPkceFlowIdToRedirects` enabled it also arrives on
|
|
1066
|
+
* your callback URL as the reserved `sb_flow_id` query parameter (read
|
|
1067
|
+
* automatically in a browser).
|
|
1068
|
+
* - When a flow id is present but its stored verifier is gone (evicted,
|
|
1069
|
+
* already used, or from another device), the call fails with a verifier
|
|
1070
|
+
* missing error instead of trying another flow's verifier — a mismatched
|
|
1071
|
+
* verifier would consume the single-use code. Without any flow id the
|
|
1072
|
+
* most recently stored verifier is used, as before.
|
|
1029
1073
|
*
|
|
1030
1074
|
* @example Exchange Auth Code
|
|
1031
1075
|
* ```js
|
|
1032
1076
|
* supabase.auth.exchangeCodeForSession('34e770dd-9ff9-416c-87fa-43b31d7ef225')
|
|
1033
1077
|
* ```
|
|
1034
1078
|
*
|
|
1079
|
+
* @example Exchange Auth Code for a specific flow (e.g. in a server-side callback handler)
|
|
1080
|
+
* ```js
|
|
1081
|
+
* const flowId = requestUrl.searchParams.get('sb_flow_id')
|
|
1082
|
+
* supabase.auth.exchangeCodeForSession(code, flowId ? { flowId } : undefined)
|
|
1083
|
+
* ```
|
|
1084
|
+
*
|
|
1035
1085
|
* @exampleResponse Exchange Auth Code
|
|
1036
1086
|
* ```json
|
|
1037
1087
|
* {
|
|
@@ -1189,15 +1239,15 @@ class GoTrueClient {
|
|
|
1189
1239
|
* }
|
|
1190
1240
|
* ```
|
|
1191
1241
|
*/
|
|
1192
|
-
async exchangeCodeForSession(authCode) {
|
|
1242
|
+
async exchangeCodeForSession(authCode, options) {
|
|
1193
1243
|
await this.initializePromise;
|
|
1194
1244
|
if (this.lock != null) {
|
|
1195
1245
|
// TODO(v3): remove legacy lock path
|
|
1196
1246
|
return this._acquireLock(this.lockAcquireTimeout, async () => {
|
|
1197
|
-
return this._exchangeCodeForSession(authCode);
|
|
1247
|
+
return this._exchangeCodeForSession(authCode, options);
|
|
1198
1248
|
});
|
|
1199
1249
|
}
|
|
1200
|
-
return this._exchangeCodeForSession(authCode);
|
|
1250
|
+
return this._exchangeCodeForSession(authCode, options);
|
|
1201
1251
|
}
|
|
1202
1252
|
/**
|
|
1203
1253
|
* Signs in a user by verifying a message signed by the user's private key.
|
|
@@ -1539,8 +1589,23 @@ class GoTrueClient {
|
|
|
1539
1589
|
throw error;
|
|
1540
1590
|
}
|
|
1541
1591
|
}
|
|
1542
|
-
async _exchangeCodeForSession(authCode) {
|
|
1543
|
-
const
|
|
1592
|
+
async _exchangeCodeForSession(authCode, options) {
|
|
1593
|
+
const hasExplicitFlowId = (options === null || options === void 0 ? void 0 : options.flowId) != null;
|
|
1594
|
+
const requestedFlowId = hasExplicitFlowId
|
|
1595
|
+
? validatePKCEFlowId(options === null || options === void 0 ? void 0 : options.flowId)
|
|
1596
|
+
: isBrowser()
|
|
1597
|
+
? validatePKCEFlowId(parseParametersFromURL(window.location.href)[PKCE_FLOW_ID_PARAM])
|
|
1598
|
+
: null;
|
|
1599
|
+
if (hasExplicitFlowId && !requestedFlowId) {
|
|
1600
|
+
this._debug('#_exchangeCodeForSession()', 'provided flowId is not a valid flow id', options === null || options === void 0 ? void 0 : options.flowId);
|
|
1601
|
+
}
|
|
1602
|
+
// With a flow id (explicit or from the callback URL) the lookup is
|
|
1603
|
+
// slot-only and a miss fails fast — see retrievePKCEVerifier. An invalid
|
|
1604
|
+
// explicit flow id also fails fast rather than borrowing another flow's
|
|
1605
|
+
// verifier.
|
|
1606
|
+
const { verifier: storageItem, flowId } = hasExplicitFlowId && !requestedFlowId
|
|
1607
|
+
? { verifier: null, flowId: null }
|
|
1608
|
+
: await retrievePKCEVerifier(this.storage, this.storageKey, requestedFlowId);
|
|
1544
1609
|
const [codeVerifier, redirectType] = (storageItem !== null && storageItem !== void 0 ? storageItem : '').split('/');
|
|
1545
1610
|
try {
|
|
1546
1611
|
if (!codeVerifier && this.flowType === 'pkce') {
|
|
@@ -1554,7 +1619,7 @@ class GoTrueClient {
|
|
|
1554
1619
|
},
|
|
1555
1620
|
xform: _sessionResponse,
|
|
1556
1621
|
});
|
|
1557
|
-
await
|
|
1622
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
1558
1623
|
if (error) {
|
|
1559
1624
|
throw error;
|
|
1560
1625
|
}
|
|
@@ -1572,7 +1637,7 @@ class GoTrueClient {
|
|
|
1572
1637
|
return this._returnResult({ data: Object.assign(Object.assign({}, data), { redirectType: redirectType !== null && redirectType !== void 0 ? redirectType : null }), error });
|
|
1573
1638
|
}
|
|
1574
1639
|
catch (error) {
|
|
1575
|
-
await
|
|
1640
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
1576
1641
|
if (isAuthError(error)) {
|
|
1577
1642
|
return this._returnResult({
|
|
1578
1643
|
data: { user: null, session: null, redirectType: null },
|
|
@@ -1771,6 +1836,7 @@ class GoTrueClient {
|
|
|
1771
1836
|
*/
|
|
1772
1837
|
async signInWithOtp(credentials) {
|
|
1773
1838
|
var _a, _b, _c, _d, _f;
|
|
1839
|
+
let flowId = null;
|
|
1774
1840
|
try {
|
|
1775
1841
|
if ('email' in credentials) {
|
|
1776
1842
|
const { email, options } = credentials;
|
|
@@ -1778,7 +1844,7 @@ class GoTrueClient {
|
|
|
1778
1844
|
let codeChallengeMethod = null;
|
|
1779
1845
|
if (this.flowType === 'pkce') {
|
|
1780
1846
|
;
|
|
1781
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
1847
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
1782
1848
|
}
|
|
1783
1849
|
const { error } = await _request(this.fetch, 'POST', `${this.url}/otp`, {
|
|
1784
1850
|
headers: this.headers,
|
|
@@ -1790,7 +1856,7 @@ class GoTrueClient {
|
|
|
1790
1856
|
code_challenge: codeChallenge,
|
|
1791
1857
|
code_challenge_method: codeChallengeMethod,
|
|
1792
1858
|
},
|
|
1793
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
1859
|
+
redirectTo: this._maybeAppendFlowIdToRedirect(options === null || options === void 0 ? void 0 : options.emailRedirectTo, flowId),
|
|
1794
1860
|
});
|
|
1795
1861
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
1796
1862
|
}
|
|
@@ -1814,7 +1880,7 @@ class GoTrueClient {
|
|
|
1814
1880
|
throw new AuthInvalidCredentialsError('You must provide either an email or phone number.');
|
|
1815
1881
|
}
|
|
1816
1882
|
catch (error) {
|
|
1817
|
-
await
|
|
1883
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
1818
1884
|
if (isAuthError(error)) {
|
|
1819
1885
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
1820
1886
|
}
|
|
@@ -2049,29 +2115,30 @@ class GoTrueClient {
|
|
|
2049
2115
|
* ```
|
|
2050
2116
|
*/
|
|
2051
2117
|
async signInWithSSO(params) {
|
|
2052
|
-
var _a, _b, _c, _d
|
|
2118
|
+
var _a, _b, _c, _d;
|
|
2119
|
+
let flowId = null;
|
|
2053
2120
|
try {
|
|
2054
2121
|
let codeChallenge = null;
|
|
2055
2122
|
let codeChallengeMethod = null;
|
|
2056
2123
|
if (this.flowType === 'pkce') {
|
|
2057
2124
|
;
|
|
2058
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
2125
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
2059
2126
|
}
|
|
2060
2127
|
const result = await _request(this.fetch, 'POST', `${this.url}/sso`, {
|
|
2061
|
-
body: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ('providerId' in params ? { provider_id: params.providerId } : null)), ('domain' in params ? { domain: params.domain } : null)), { redirect_to: (
|
|
2128
|
+
body: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ('providerId' in params ? { provider_id: params.providerId } : null)), ('domain' in params ? { domain: params.domain } : null)), { redirect_to: this._maybeAppendFlowIdToRedirect((_a = params.options) === null || _a === void 0 ? void 0 : _a.redirectTo, flowId) }), (((_b = params === null || params === void 0 ? void 0 : params.options) === null || _b === void 0 ? void 0 : _b.captchaToken)
|
|
2062
2129
|
? { gotrue_meta_security: { captcha_token: params.options.captchaToken } }
|
|
2063
2130
|
: null)), { skip_http_redirect: true, code_challenge: codeChallenge, code_challenge_method: codeChallengeMethod }),
|
|
2064
2131
|
headers: this.headers,
|
|
2065
2132
|
xform: _ssoResponse,
|
|
2066
2133
|
});
|
|
2067
2134
|
// Automatically redirect in browser unless skipBrowserRedirect is true
|
|
2068
|
-
if (((
|
|
2135
|
+
if (((_c = result.data) === null || _c === void 0 ? void 0 : _c.url) && isBrowser() && !((_d = params.options) === null || _d === void 0 ? void 0 : _d.skipBrowserRedirect)) {
|
|
2069
2136
|
window.location.assign(result.data.url);
|
|
2070
2137
|
}
|
|
2071
2138
|
return this._returnResult(result);
|
|
2072
2139
|
}
|
|
2073
2140
|
catch (error) {
|
|
2074
|
-
await
|
|
2141
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
2075
2142
|
if (isAuthError(error)) {
|
|
2076
2143
|
return this._returnResult({ data: null, error });
|
|
2077
2144
|
}
|
|
@@ -2191,6 +2258,7 @@ class GoTrueClient {
|
|
|
2191
2258
|
* ```
|
|
2192
2259
|
*/
|
|
2193
2260
|
async resend(credentials) {
|
|
2261
|
+
let flowId = null;
|
|
2194
2262
|
try {
|
|
2195
2263
|
const endpoint = `${this.url}/resend`;
|
|
2196
2264
|
if ('email' in credentials) {
|
|
@@ -2199,7 +2267,7 @@ class GoTrueClient {
|
|
|
2199
2267
|
let codeChallengeMethod = null;
|
|
2200
2268
|
if (this.flowType === 'pkce') {
|
|
2201
2269
|
;
|
|
2202
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
2270
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
2203
2271
|
}
|
|
2204
2272
|
const { error } = await _request(this.fetch, 'POST', endpoint, {
|
|
2205
2273
|
headers: this.headers,
|
|
@@ -2210,10 +2278,10 @@ class GoTrueClient {
|
|
|
2210
2278
|
code_challenge: codeChallenge,
|
|
2211
2279
|
code_challenge_method: codeChallengeMethod,
|
|
2212
2280
|
},
|
|
2213
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
2281
|
+
redirectTo: this._maybeAppendFlowIdToRedirect(options === null || options === void 0 ? void 0 : options.emailRedirectTo, flowId),
|
|
2214
2282
|
});
|
|
2215
2283
|
if (error) {
|
|
2216
|
-
await
|
|
2284
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
2217
2285
|
}
|
|
2218
2286
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
2219
2287
|
}
|
|
@@ -2235,7 +2303,7 @@ class GoTrueClient {
|
|
|
2235
2303
|
throw new AuthInvalidCredentialsError('You must provide either an email or phone number and a type');
|
|
2236
2304
|
}
|
|
2237
2305
|
catch (error) {
|
|
2238
|
-
await
|
|
2306
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
2239
2307
|
if (isAuthError(error)) {
|
|
2240
2308
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
2241
2309
|
}
|
|
@@ -2251,7 +2319,7 @@ class GoTrueClient {
|
|
|
2251
2319
|
* to the client. If that storage is based on request cookies for example,
|
|
2252
2320
|
* the values in it may not be authentic and therefore it's strongly advised
|
|
2253
2321
|
* against using this method and its results in such circumstances. A warning
|
|
2254
|
-
* will be emitted if this is detected. Use {@link
|
|
2322
|
+
* will be emitted if this is detected. Use {@link GoTrueClient.getUser} instead.
|
|
2255
2323
|
*
|
|
2256
2324
|
* @category Auth
|
|
2257
2325
|
*
|
|
@@ -2402,7 +2470,7 @@ class GoTrueClient {
|
|
|
2402
2470
|
}
|
|
2403
2471
|
}
|
|
2404
2472
|
/**
|
|
2405
|
-
* Use instead of {@link
|
|
2473
|
+
* Use instead of {@link GoTrueClient.getSession} inside the library. Loads the session
|
|
2406
2474
|
* via `__loadSession` (which may trigger a refresh if the access token is
|
|
2407
2475
|
* within the expiry margin) and runs `fn` with the result.
|
|
2408
2476
|
*/
|
|
@@ -2423,7 +2491,7 @@ class GoTrueClient {
|
|
|
2423
2491
|
/**
|
|
2424
2492
|
* NEVER USE DIRECTLY!
|
|
2425
2493
|
*
|
|
2426
|
-
* Always use
|
|
2494
|
+
* Always use `_useSession`.
|
|
2427
2495
|
*/
|
|
2428
2496
|
async __loadSession() {
|
|
2429
2497
|
this._debug('#__loadSession()', 'begin');
|
|
@@ -2637,7 +2705,6 @@ class GoTrueClient {
|
|
|
2637
2705
|
// JWT contains a `session_id` which does not correspond to an active
|
|
2638
2706
|
// session in the database, indicating the user is signed out.
|
|
2639
2707
|
await this._removeSession();
|
|
2640
|
-
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`);
|
|
2641
2708
|
}
|
|
2642
2709
|
return this._returnResult({ data: { user: null }, error });
|
|
2643
2710
|
}
|
|
@@ -2769,6 +2836,7 @@ class GoTrueClient {
|
|
|
2769
2836
|
return await this._updateUser(attributes, options);
|
|
2770
2837
|
}
|
|
2771
2838
|
async _updateUser(attributes, options = {}) {
|
|
2839
|
+
let flowId = null;
|
|
2772
2840
|
try {
|
|
2773
2841
|
return await this._useSession(async (result) => {
|
|
2774
2842
|
const { data: sessionData, error: sessionError } = result;
|
|
@@ -2783,11 +2851,11 @@ class GoTrueClient {
|
|
|
2783
2851
|
let codeChallengeMethod = null;
|
|
2784
2852
|
if (this.flowType === 'pkce' && attributes.email != null) {
|
|
2785
2853
|
;
|
|
2786
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
2854
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
2787
2855
|
}
|
|
2788
2856
|
const { data, error: userError } = await _request(this.fetch, 'PUT', `${this.url}/user`, {
|
|
2789
2857
|
headers: this.headers,
|
|
2790
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
2858
|
+
redirectTo: this._maybeAppendFlowIdToRedirect(options === null || options === void 0 ? void 0 : options.emailRedirectTo, flowId),
|
|
2791
2859
|
body: Object.assign(Object.assign({}, attributes), { code_challenge: codeChallenge, code_challenge_method: codeChallengeMethod }),
|
|
2792
2860
|
jwt: session.access_token,
|
|
2793
2861
|
xform: _userResponse,
|
|
@@ -2802,7 +2870,7 @@ class GoTrueClient {
|
|
|
2802
2870
|
});
|
|
2803
2871
|
}
|
|
2804
2872
|
catch (error) {
|
|
2805
|
-
await
|
|
2873
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
2806
2874
|
if (isAuthError(error)) {
|
|
2807
2875
|
return this._returnResult({ data: { user: null }, error });
|
|
2808
2876
|
}
|
|
@@ -3195,11 +3263,14 @@ class GoTrueClient {
|
|
|
3195
3263
|
this._debug('#_initialize()', 'begin', 'is PKCE flow', true);
|
|
3196
3264
|
if (!params.code)
|
|
3197
3265
|
throw new AuthPKCEGrantCodeExchangeError('No code detected.');
|
|
3198
|
-
const { data, error } = await this._exchangeCodeForSession(params.code
|
|
3266
|
+
const { data, error } = await this._exchangeCodeForSession(params.code, {
|
|
3267
|
+
flowId: params[PKCE_FLOW_ID_PARAM],
|
|
3268
|
+
});
|
|
3199
3269
|
if (error)
|
|
3200
3270
|
throw error;
|
|
3201
3271
|
const url = new URL(window.location.href);
|
|
3202
3272
|
url.searchParams.delete('code');
|
|
3273
|
+
url.searchParams.delete(PKCE_FLOW_ID_PARAM);
|
|
3203
3274
|
window.history.replaceState(window.history.state, '', url.toString());
|
|
3204
3275
|
return {
|
|
3205
3276
|
data: { session: data.session, redirectType: (_a = data.redirectType) !== null && _a !== void 0 ? _a : null },
|
|
@@ -3269,8 +3340,16 @@ class GoTrueClient {
|
|
|
3269
3340
|
* Checks if the current URL and backing storage contain parameters given by a PKCE flow
|
|
3270
3341
|
*/
|
|
3271
3342
|
async _isPKCECallback(params) {
|
|
3343
|
+
if (!params.code) {
|
|
3344
|
+
return false;
|
|
3345
|
+
}
|
|
3346
|
+
const flowId = validatePKCEFlowId(params[PKCE_FLOW_ID_PARAM]);
|
|
3347
|
+
if (flowId &&
|
|
3348
|
+
(await getItemAsync(this.storage, pkceVerifierSlotKey(this.storageKey, flowId)))) {
|
|
3349
|
+
return true;
|
|
3350
|
+
}
|
|
3272
3351
|
const currentStorageContent = await getItemAsync(this.storage, `${this.storageKey}-code-verifier`);
|
|
3273
|
-
return !!
|
|
3352
|
+
return !!currentStorageContent;
|
|
3274
3353
|
}
|
|
3275
3354
|
/**
|
|
3276
3355
|
* Inside a browser context, `signOut()` will remove the logged in user from the browser session and log them out - removing all items from localstorage and then trigger a `"SIGNED_OUT"` event.
|
|
@@ -3326,6 +3405,9 @@ class GoTrueClient {
|
|
|
3326
3405
|
async _signOut({ scope } = { scope: 'global' }) {
|
|
3327
3406
|
return await this._useSession(async (result) => {
|
|
3328
3407
|
var _a;
|
|
3408
|
+
const removeCurrentSession = async () => {
|
|
3409
|
+
await this._removeSession();
|
|
3410
|
+
};
|
|
3329
3411
|
const { data, error: sessionError } = result;
|
|
3330
3412
|
if (sessionError && !isAuthSessionMissingError(sessionError)) {
|
|
3331
3413
|
return this._returnResult({ error: sessionError });
|
|
@@ -3339,13 +3421,15 @@ class GoTrueClient {
|
|
|
3339
3421
|
if (!((isAuthApiError(error) &&
|
|
3340
3422
|
(error.status === 404 || error.status === 401 || error.status === 403)) ||
|
|
3341
3423
|
isAuthSessionMissingError(error))) {
|
|
3424
|
+
if (scope !== 'others') {
|
|
3425
|
+
await removeCurrentSession();
|
|
3426
|
+
}
|
|
3342
3427
|
return this._returnResult({ error });
|
|
3343
3428
|
}
|
|
3344
3429
|
}
|
|
3345
3430
|
}
|
|
3346
3431
|
if (scope !== 'others') {
|
|
3347
|
-
await
|
|
3348
|
-
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`);
|
|
3432
|
+
await removeCurrentSession();
|
|
3349
3433
|
}
|
|
3350
3434
|
return this._returnResult({ error: null });
|
|
3351
3435
|
});
|
|
@@ -3566,7 +3650,16 @@ class GoTrueClient {
|
|
|
3566
3650
|
catch (err) {
|
|
3567
3651
|
await ((_b = this.stateChangeEmitters.get(id)) === null || _b === void 0 ? void 0 : _b.callback('INITIAL_SESSION', null));
|
|
3568
3652
|
this._debug('INITIAL_SESSION', 'callback id', id, 'error', err);
|
|
3569
|
-
if (isAuthSessionMissingError(err)
|
|
3653
|
+
if (isAuthSessionMissingError(err) ||
|
|
3654
|
+
isAuthRetryableFetchError(err) ||
|
|
3655
|
+
(isAuthApiError(err) &&
|
|
3656
|
+
(err.code === 'refresh_token_not_found' ||
|
|
3657
|
+
err.code === 'refresh_token_already_used' ||
|
|
3658
|
+
err.code === 'session_expired'))) {
|
|
3659
|
+
// A missing session, a transient/aborted network failure (e.g. a
|
|
3660
|
+
// superseded page navigation cancelling the in-flight request), or
|
|
3661
|
+
// a dead refresh token (e.g. stale SSR cookies) is not an
|
|
3662
|
+
// application error — warn rather than surface it raw.
|
|
3570
3663
|
console.warn(err);
|
|
3571
3664
|
}
|
|
3572
3665
|
else {
|
|
@@ -3645,9 +3738,10 @@ class GoTrueClient {
|
|
|
3645
3738
|
async resetPasswordForEmail(email, options = {}) {
|
|
3646
3739
|
let codeChallenge = null;
|
|
3647
3740
|
let codeChallengeMethod = null;
|
|
3741
|
+
let flowId = null;
|
|
3648
3742
|
if (this.flowType === 'pkce') {
|
|
3649
3743
|
;
|
|
3650
|
-
[codeChallenge, codeChallengeMethod] = await
|
|
3744
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod(true // isPasswordRecovery
|
|
3651
3745
|
);
|
|
3652
3746
|
}
|
|
3653
3747
|
try {
|
|
@@ -3659,11 +3753,11 @@ class GoTrueClient {
|
|
|
3659
3753
|
gotrue_meta_security: { captcha_token: options.captchaToken },
|
|
3660
3754
|
},
|
|
3661
3755
|
headers: this.headers,
|
|
3662
|
-
redirectTo: options.redirectTo,
|
|
3756
|
+
redirectTo: this._maybeAppendFlowIdToRedirect(options.redirectTo, flowId),
|
|
3663
3757
|
});
|
|
3664
3758
|
}
|
|
3665
3759
|
catch (error) {
|
|
3666
|
-
await
|
|
3760
|
+
await removePKCEVerifier(this.storage, this.storageKey, flowId);
|
|
3667
3761
|
if (isAuthError(error)) {
|
|
3668
3762
|
return this._returnResult({ data: null, error });
|
|
3669
3763
|
}
|
|
@@ -3746,7 +3840,8 @@ class GoTrueClient {
|
|
|
3746
3840
|
* {
|
|
3747
3841
|
* data: {
|
|
3748
3842
|
* provider: 'github',
|
|
3749
|
-
* url: <PROVIDER_URL_TO_REDIRECT_TO
|
|
3843
|
+
* url: <PROVIDER_URL_TO_REDIRECT_TO>,
|
|
3844
|
+
* flowId: <PKCE_FLOW_ID_OR_NULL>
|
|
3750
3845
|
* },
|
|
3751
3846
|
* error: null
|
|
3752
3847
|
* }
|
|
@@ -3760,18 +3855,20 @@ class GoTrueClient {
|
|
|
3760
3855
|
}
|
|
3761
3856
|
async linkIdentityOAuth(credentials) {
|
|
3762
3857
|
var _a;
|
|
3858
|
+
let flowId = null;
|
|
3763
3859
|
try {
|
|
3764
3860
|
const { data, error } = await this._useSession(async (result) => {
|
|
3765
3861
|
var _a, _b, _c, _d, _f;
|
|
3766
3862
|
const { data, error } = result;
|
|
3767
3863
|
if (error)
|
|
3768
3864
|
throw error;
|
|
3769
|
-
const url = await this._getUrlForProvider(`${this.url}/user/identities/authorize`, credentials.provider, {
|
|
3865
|
+
const { url, flowId: urlFlowId } = await this._getUrlForProvider(`${this.url}/user/identities/authorize`, credentials.provider, {
|
|
3770
3866
|
redirectTo: (_a = credentials.options) === null || _a === void 0 ? void 0 : _a.redirectTo,
|
|
3771
3867
|
scopes: (_b = credentials.options) === null || _b === void 0 ? void 0 : _b.scopes,
|
|
3772
3868
|
queryParams: (_c = credentials.options) === null || _c === void 0 ? void 0 : _c.queryParams,
|
|
3773
3869
|
skipBrowserRedirect: true,
|
|
3774
3870
|
});
|
|
3871
|
+
flowId = urlFlowId;
|
|
3775
3872
|
return await _request(this.fetch, 'GET', url, {
|
|
3776
3873
|
headers: this.headers,
|
|
3777
3874
|
jwt: (_f = (_d = data.session) === null || _d === void 0 ? void 0 : _d.access_token) !== null && _f !== void 0 ? _f : undefined,
|
|
@@ -3783,13 +3880,16 @@ class GoTrueClient {
|
|
|
3783
3880
|
window.location.assign(data === null || data === void 0 ? void 0 : data.url);
|
|
3784
3881
|
}
|
|
3785
3882
|
return this._returnResult({
|
|
3786
|
-
data: { provider: credentials.provider, url: data === null || data === void 0 ? void 0 : data.url },
|
|
3883
|
+
data: { provider: credentials.provider, url: data === null || data === void 0 ? void 0 : data.url, flowId },
|
|
3787
3884
|
error: null,
|
|
3788
3885
|
});
|
|
3789
3886
|
}
|
|
3790
3887
|
catch (error) {
|
|
3791
3888
|
if (isAuthError(error)) {
|
|
3792
|
-
return this._returnResult({
|
|
3889
|
+
return this._returnResult({
|
|
3890
|
+
data: { provider: credentials.provider, url: null, flowId },
|
|
3891
|
+
error,
|
|
3892
|
+
});
|
|
3793
3893
|
}
|
|
3794
3894
|
throw error;
|
|
3795
3895
|
}
|
|
@@ -3832,7 +3932,7 @@ class GoTrueClient {
|
|
|
3832
3932
|
return this._returnResult({ data, error });
|
|
3833
3933
|
}
|
|
3834
3934
|
catch (error) {
|
|
3835
|
-
await
|
|
3935
|
+
await removePKCEVerifier(this.storage, this.storageKey, null);
|
|
3836
3936
|
if (isAuthError(error)) {
|
|
3837
3937
|
return this._returnResult({ data: { user: null, session: null }, error });
|
|
3838
3938
|
}
|
|
@@ -3937,7 +4037,7 @@ class GoTrueClient {
|
|
|
3937
4037
|
return isValidSession;
|
|
3938
4038
|
}
|
|
3939
4039
|
async _handleProviderSignIn(provider, options) {
|
|
3940
|
-
const url = await this._getUrlForProvider(`${this.url}/authorize`, provider, {
|
|
4040
|
+
const { url, flowId } = await this._getUrlForProvider(`${this.url}/authorize`, provider, {
|
|
3941
4041
|
redirectTo: options.redirectTo,
|
|
3942
4042
|
scopes: options.scopes,
|
|
3943
4043
|
queryParams: options.queryParams,
|
|
@@ -3947,7 +4047,7 @@ class GoTrueClient {
|
|
|
3947
4047
|
if (isBrowser() && !options.skipBrowserRedirect) {
|
|
3948
4048
|
window.location.assign(url);
|
|
3949
4049
|
}
|
|
3950
|
-
return { data: { provider, url }, error: null };
|
|
4050
|
+
return { data: { provider, url, flowId }, error: null };
|
|
3951
4051
|
}
|
|
3952
4052
|
/**
|
|
3953
4053
|
* Recovers the session from LocalStorage and refreshes the token
|
|
@@ -4044,7 +4144,16 @@ class GoTrueClient {
|
|
|
4044
4144
|
}
|
|
4045
4145
|
catch (err) {
|
|
4046
4146
|
this._debug(debugName, 'error', err);
|
|
4047
|
-
|
|
4147
|
+
if (isAuthRetryableFetchError(err)) {
|
|
4148
|
+
// Transient/aborted network failure during session recovery (e.g. a
|
|
4149
|
+
// superseded page navigation cancelling the in-flight request). Warn
|
|
4150
|
+
// rather than surface it raw; the session is untouched and recovery
|
|
4151
|
+
// will run again on the next load.
|
|
4152
|
+
console.warn(err);
|
|
4153
|
+
}
|
|
4154
|
+
else {
|
|
4155
|
+
console.error(err);
|
|
4156
|
+
}
|
|
4048
4157
|
return;
|
|
4049
4158
|
}
|
|
4050
4159
|
finally {
|
|
@@ -4194,6 +4303,19 @@ class GoTrueClient {
|
|
|
4194
4303
|
}
|
|
4195
4304
|
}
|
|
4196
4305
|
async _notifyAllSubscribers(event, session, broadcast = true) {
|
|
4306
|
+
if (this._pendingInitNotifications !== null && broadcast) {
|
|
4307
|
+
// We're inside initialize() before initializePromise has resolved, and
|
|
4308
|
+
// this notification originates from the init chain (_recoverAndRefresh),
|
|
4309
|
+
// which always fires with broadcast = true. Enqueue instead of firing so
|
|
4310
|
+
// that callbacks can safely call getSession() / getUser() without
|
|
4311
|
+
// deadlocking on initializePromise.
|
|
4312
|
+
//
|
|
4313
|
+
// Notifications with broadcast = false come from the incoming
|
|
4314
|
+
// BroadcastChannel handler (a cross-tab event), not the init chain, so
|
|
4315
|
+
// they are fired immediately to preserve multi-tab ordering.
|
|
4316
|
+
this._pendingInitNotifications.push({ event, session, broadcast });
|
|
4317
|
+
return;
|
|
4318
|
+
}
|
|
4197
4319
|
const debugName = `#_notifyAllSubscribers(${event})`;
|
|
4198
4320
|
this._debug(debugName, 'begin', session, `broadcast = ${broadcast}`);
|
|
4199
4321
|
try {
|
|
@@ -4230,7 +4352,6 @@ class GoTrueClient {
|
|
|
4230
4352
|
// _saveSession is always called whenever a new session has been acquired
|
|
4231
4353
|
// so we can safely suppress the warning returned by future getSession calls
|
|
4232
4354
|
this.suppressGetSessionWarning = true;
|
|
4233
|
-
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`);
|
|
4234
4355
|
// Create a shallow copy to work with, to avoid mutating the original session object if it's used elsewhere
|
|
4235
4356
|
const sessionToProcess = Object.assign({}, session);
|
|
4236
4357
|
const userIsProxy = sessionToProcess.user && sessionToProcess.user.__isUserNotAvailableProxy === true;
|
|
@@ -4274,7 +4395,7 @@ class GoTrueClient {
|
|
|
4274
4395
|
this.lastRefreshFailure = null;
|
|
4275
4396
|
this.suppressGetSessionWarning = false;
|
|
4276
4397
|
await removeItemAsync(this.storage, this.storageKey);
|
|
4277
|
-
await
|
|
4398
|
+
await removeAllPKCEVerifiers(this.storage, this.storageKey);
|
|
4278
4399
|
await removeItemAsync(this.storage, this.storageKey + '-user');
|
|
4279
4400
|
if (this.userStorage) {
|
|
4280
4401
|
await removeItemAsync(this.userStorage, this.storageKey + '-user');
|
|
@@ -4284,8 +4405,8 @@ class GoTrueClient {
|
|
|
4284
4405
|
/**
|
|
4285
4406
|
* Removes any registered visibilitychange callback.
|
|
4286
4407
|
*
|
|
4287
|
-
* {@
|
|
4288
|
-
* {@
|
|
4408
|
+
* {@link GoTrueClient.startAutoRefresh}
|
|
4409
|
+
* {@link GoTrueClient.stopAutoRefresh}
|
|
4289
4410
|
*/
|
|
4290
4411
|
_removeVisibilityChangedCallback() {
|
|
4291
4412
|
this._debug('#_removeVisibilityChangedCallback()');
|
|
@@ -4301,7 +4422,7 @@ class GoTrueClient {
|
|
|
4301
4422
|
}
|
|
4302
4423
|
}
|
|
4303
4424
|
/**
|
|
4304
|
-
* This is the private implementation of {@link
|
|
4425
|
+
* This is the private implementation of {@link GoTrueClient.startAutoRefresh}. Use this
|
|
4305
4426
|
* within the library.
|
|
4306
4427
|
*/
|
|
4307
4428
|
async _startAutoRefresh() {
|
|
@@ -4343,7 +4464,7 @@ class GoTrueClient {
|
|
|
4343
4464
|
}
|
|
4344
4465
|
}
|
|
4345
4466
|
/**
|
|
4346
|
-
* This is the private implementation of {@link
|
|
4467
|
+
* This is the private implementation of {@link GoTrueClient.stopAutoRefresh}. Use this
|
|
4347
4468
|
* within the library.
|
|
4348
4469
|
*/
|
|
4349
4470
|
async _stopAutoRefresh() {
|
|
@@ -4379,7 +4500,7 @@ class GoTrueClient {
|
|
|
4379
4500
|
* platform's foreground indication mechanism and call these methods
|
|
4380
4501
|
* appropriately to conserve resources.
|
|
4381
4502
|
*
|
|
4382
|
-
* {@
|
|
4503
|
+
* {@link GoTrueClient.stopAutoRefresh}
|
|
4383
4504
|
*
|
|
4384
4505
|
* @category Auth
|
|
4385
4506
|
*
|
|
@@ -4413,7 +4534,7 @@ class GoTrueClient {
|
|
|
4413
4534
|
* If you call this method any managed visibility change callback will be
|
|
4414
4535
|
* removed and you must manage visibility changes on your own.
|
|
4415
4536
|
*
|
|
4416
|
-
* See {@link
|
|
4537
|
+
* See {@link GoTrueClient.startAutoRefresh} for more details.
|
|
4417
4538
|
*
|
|
4418
4539
|
* @category Auth
|
|
4419
4540
|
*
|
|
@@ -4640,15 +4761,23 @@ class GoTrueClient {
|
|
|
4640
4761
|
* @param options.queryParams An object of key-value pairs containing query parameters granted to the OAuth application.
|
|
4641
4762
|
*/
|
|
4642
4763
|
async _getUrlForProvider(url, provider, options) {
|
|
4764
|
+
let redirectTo = options === null || options === void 0 ? void 0 : options.redirectTo;
|
|
4765
|
+
let codeChallenge = null;
|
|
4766
|
+
let codeChallengeMethod = null;
|
|
4767
|
+
let flowId = null;
|
|
4768
|
+
if (this.flowType === 'pkce') {
|
|
4769
|
+
;
|
|
4770
|
+
[codeChallenge, codeChallengeMethod, flowId] = await this._getCodeChallengeAndMethod();
|
|
4771
|
+
redirectTo = this._maybeAppendFlowIdToRedirect(redirectTo, flowId);
|
|
4772
|
+
}
|
|
4643
4773
|
const urlParams = [`provider=${encodeURIComponent(provider)}`];
|
|
4644
|
-
if (
|
|
4645
|
-
urlParams.push(`redirect_to=${encodeURIComponent(
|
|
4774
|
+
if (redirectTo) {
|
|
4775
|
+
urlParams.push(`redirect_to=${encodeURIComponent(redirectTo)}`);
|
|
4646
4776
|
}
|
|
4647
4777
|
if (options === null || options === void 0 ? void 0 : options.scopes) {
|
|
4648
4778
|
urlParams.push(`scopes=${encodeURIComponent(options.scopes)}`);
|
|
4649
4779
|
}
|
|
4650
|
-
if (
|
|
4651
|
-
const [codeChallenge, codeChallengeMethod] = await getCodeChallengeAndMethod(this.storage, this.storageKey);
|
|
4780
|
+
if (codeChallenge != null && codeChallengeMethod != null) {
|
|
4652
4781
|
const flowParams = new URLSearchParams({
|
|
4653
4782
|
code_challenge: `${encodeURIComponent(codeChallenge)}`,
|
|
4654
4783
|
code_challenge_method: `${encodeURIComponent(codeChallengeMethod)}`,
|
|
@@ -4662,7 +4791,27 @@ class GoTrueClient {
|
|
|
4662
4791
|
if (options === null || options === void 0 ? void 0 : options.skipBrowserRedirect) {
|
|
4663
4792
|
urlParams.push(`skip_http_redirect=${options.skipBrowserRedirect}`);
|
|
4664
4793
|
}
|
|
4665
|
-
return `${url}?${urlParams.join('&')}
|
|
4794
|
+
return { url: `${url}?${urlParams.join('&')}`, flowId };
|
|
4795
|
+
}
|
|
4796
|
+
/**
|
|
4797
|
+
* Appends the reserved flow id parameter to a redirect URL so the callback
|
|
4798
|
+
* can be matched to the verifier stored for its flow. Opt-in via
|
|
4799
|
+
* `experimental.appendPkceFlowIdToRedirects`: redirect URLs are validated
|
|
4800
|
+
* against the project's allow list including the query string, so an extra
|
|
4801
|
+
* parameter can stop exact (non-wildcard) entries from matching.
|
|
4802
|
+
*/
|
|
4803
|
+
_maybeAppendFlowIdToRedirect(redirectTo, flowId) {
|
|
4804
|
+
if (!redirectTo || !flowId || !this.experimental.appendPkceFlowIdToRedirects) {
|
|
4805
|
+
return redirectTo !== null && redirectTo !== void 0 ? redirectTo : undefined;
|
|
4806
|
+
}
|
|
4807
|
+
return appendFlowIdToRedirectTo(redirectTo, flowId);
|
|
4808
|
+
}
|
|
4809
|
+
/**
|
|
4810
|
+
* Generates and stores a PKCE challenge/verifier pair for a new flow,
|
|
4811
|
+
* logging any pending verifier the bounded slot ring evicts.
|
|
4812
|
+
*/
|
|
4813
|
+
async _getCodeChallengeAndMethod(isPasswordRecovery = false) {
|
|
4814
|
+
return getCodeChallengeAndMethod(this.storage, this.storageKey, isPasswordRecovery, (evictedFlowId) => this._debug('#_getCodeChallengeAndMethod()', 'evicted oldest pending PKCE verifier slot', evictedFlowId));
|
|
4666
4815
|
}
|
|
4667
4816
|
async _unenroll(params) {
|
|
4668
4817
|
try {
|
|
@@ -4810,7 +4959,7 @@ class GoTrueClient {
|
|
|
4810
4959
|
return run();
|
|
4811
4960
|
}
|
|
4812
4961
|
/**
|
|
4813
|
-
* {@
|
|
4962
|
+
* {@link GoTrueMFAApi#challengeAndVerify}
|
|
4814
4963
|
*/
|
|
4815
4964
|
async _challengeAndVerify(params) {
|
|
4816
4965
|
const { data: challengeData, error: challengeError } = await this._challenge({
|
|
@@ -4826,7 +4975,7 @@ class GoTrueClient {
|
|
|
4826
4975
|
});
|
|
4827
4976
|
}
|
|
4828
4977
|
/**
|
|
4829
|
-
* {@
|
|
4978
|
+
* {@link GoTrueMFAApi#listFactors}
|
|
4830
4979
|
*/
|
|
4831
4980
|
async _listFactors() {
|
|
4832
4981
|
var _a;
|
|
@@ -4854,7 +5003,7 @@ class GoTrueClient {
|
|
|
4854
5003
|
};
|
|
4855
5004
|
}
|
|
4856
5005
|
/**
|
|
4857
|
-
* {@
|
|
5006
|
+
* {@link GoTrueMFAApi#getAuthenticatorAssuranceLevel}
|
|
4858
5007
|
*/
|
|
4859
5008
|
async _getAuthenticatorAssuranceLevel(jwt) {
|
|
4860
5009
|
var _a, _b, _c, _d;
|
|
@@ -5105,15 +5254,15 @@ class GoTrueClient {
|
|
|
5105
5254
|
* Extracts the JWT claims present in the access token by first verifying the
|
|
5106
5255
|
* JWT against the server's JSON Web Key Set endpoint
|
|
5107
5256
|
* `/.well-known/jwks.json` which is often cached, resulting in significantly
|
|
5108
|
-
* faster responses. Prefer this method over {@link
|
|
5257
|
+
* faster responses. Prefer this method over {@link GoTrueClient.getUser} which always
|
|
5109
5258
|
* sends a request to the Auth server for each JWT.
|
|
5110
5259
|
*
|
|
5111
5260
|
* If the project is not using an asymmetric JWT signing key (like ECC or
|
|
5112
|
-
* RSA) it always sends a request to the Auth server (similar to
|
|
5113
|
-
*
|
|
5261
|
+
* RSA) it always sends a request to the Auth server (similar to
|
|
5262
|
+
* {@link GoTrueClient.getUser}) to verify the JWT.
|
|
5114
5263
|
*
|
|
5115
5264
|
* @param jwt An optional specific JWT you wish to verify, not the one you
|
|
5116
|
-
* can obtain from {@link
|
|
5265
|
+
* can obtain from {@link GoTrueClient.getSession}.
|
|
5117
5266
|
* @param options Various additional options that allow you to customize the
|
|
5118
5267
|
* behavior of this method.
|
|
5119
5268
|
*
|