@supabase/gotrue-js 2.39.1 → 2.40.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/main/GoTrueAdminApi.js +164 -193
- package/dist/main/GoTrueAdminApi.js.map +1 -1
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +1039 -1132
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/fetch.js +51 -66
- package/dist/main/lib/fetch.js.map +1 -1
- package/dist/main/lib/helpers.js +28 -41
- package/dist/main/lib/helpers.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.js +164 -193
- package/dist/module/GoTrueAdminApi.js.map +1 -1
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +1039 -1132
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/fetch.js +51 -66
- package/dist/module/lib/fetch.js.map +1 -1
- package/dist/module/lib/helpers.js +28 -41
- package/dist/module/lib/helpers.js.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/GoTrueClient.ts +4 -1
- package/src/lib/version.ts +1 -1
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
@@ -99,10 +90,10 @@ class GoTrueClient {
|
|
|
99
90
|
catch (e) {
|
|
100
91
|
console.error('Failed to create a new BroadcastChannel, multi-tab state changes will not be available', e);
|
|
101
92
|
}
|
|
102
|
-
(_a = this.broadcastChannel) === null || _a === void 0 ? void 0 : _a.addEventListener('message', (event) =>
|
|
93
|
+
(_a = this.broadcastChannel) === null || _a === void 0 ? void 0 : _a.addEventListener('message', async (event) => {
|
|
103
94
|
this._debug('received broadcast notification from other tab or client', event);
|
|
104
|
-
|
|
105
|
-
})
|
|
95
|
+
await this._notifyAllSubscribers(event.data.event, event.data.session, false); // broadcast = false so we don't get an endless loop of messages
|
|
96
|
+
});
|
|
106
97
|
}
|
|
107
98
|
this.initialize();
|
|
108
99
|
}
|
|
@@ -129,53 +120,51 @@ class GoTrueClient {
|
|
|
129
120
|
* 2. Never return a session from this method as it would be cached over
|
|
130
121
|
* the whole lifetime of the client
|
|
131
122
|
*/
|
|
132
|
-
_initialize() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
yield this._removeSession();
|
|
147
|
-
return { error };
|
|
148
|
-
}
|
|
149
|
-
const { session, redirectType } = data;
|
|
150
|
-
this._debug('#_initialize()', 'detected session in URL', session, 'redirect type', redirectType);
|
|
151
|
-
yield this._saveSession(session);
|
|
152
|
-
setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
if (redirectType === 'recovery') {
|
|
154
|
-
yield this._notifyAllSubscribers('PASSWORD_RECOVERY', session);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
yield this._notifyAllSubscribers('SIGNED_IN', session);
|
|
158
|
-
}
|
|
159
|
-
}), 0);
|
|
160
|
-
return { error: null };
|
|
161
|
-
}
|
|
162
|
-
// no login attempt via callback url try to recover session from storage
|
|
163
|
-
yield this._recoverAndRefresh();
|
|
164
|
-
return { error: null };
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
if ((0, errors_1.isAuthError)(error)) {
|
|
123
|
+
async _initialize() {
|
|
124
|
+
if (this.initializePromise) {
|
|
125
|
+
return this.initializePromise;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const isPKCEFlow = (0, helpers_1.isBrowser)() ? await this._isPKCEFlow() : false;
|
|
129
|
+
this._debug('#_initialize()', 'begin', 'is PKCE flow', isPKCEFlow);
|
|
130
|
+
if (isPKCEFlow || (this.detectSessionInUrl && this._isImplicitGrantFlow())) {
|
|
131
|
+
const { data, error } = await this._getSessionFromUrl(isPKCEFlow);
|
|
132
|
+
if (error) {
|
|
133
|
+
this._debug('#_initialize()', 'error detecting session from URL', error);
|
|
134
|
+
// failed login attempt via url,
|
|
135
|
+
// remove old session as in verifyOtp, signUp and signInWith*
|
|
136
|
+
await this._removeSession();
|
|
168
137
|
return { error };
|
|
169
138
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
139
|
+
const { session, redirectType } = data;
|
|
140
|
+
this._debug('#_initialize()', 'detected session in URL', session, 'redirect type', redirectType);
|
|
141
|
+
await this._saveSession(session);
|
|
142
|
+
setTimeout(async () => {
|
|
143
|
+
if (redirectType === 'recovery') {
|
|
144
|
+
await this._notifyAllSubscribers('PASSWORD_RECOVERY', session);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
await this._notifyAllSubscribers('SIGNED_IN', session);
|
|
148
|
+
}
|
|
149
|
+
}, 0);
|
|
150
|
+
return { error: null };
|
|
173
151
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
152
|
+
// no login attempt via callback url try to recover session from storage
|
|
153
|
+
await this._recoverAndRefresh();
|
|
154
|
+
return { error: null };
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
158
|
+
return { error };
|
|
177
159
|
}
|
|
178
|
-
|
|
160
|
+
return {
|
|
161
|
+
error: new errors_1.AuthUnknownError('Unexpected error during initialization', error),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
await this._handleVisibilityChange();
|
|
166
|
+
this._debug('#_initialize()', 'end');
|
|
167
|
+
}
|
|
179
168
|
}
|
|
180
169
|
/**
|
|
181
170
|
* Creates a new user.
|
|
@@ -187,72 +176,70 @@ class GoTrueClient {
|
|
|
187
176
|
* @returns A logged-in session if the server has "autoconfirm" ON
|
|
188
177
|
* @returns A user if the server has "autoconfirm" OFF
|
|
189
178
|
*/
|
|
190
|
-
signUp(credentials) {
|
|
179
|
+
async signUp(credentials) {
|
|
191
180
|
var _a, _b, _c;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
else if ('phone' in credentials) {
|
|
221
|
-
const { phone, password, options } = credentials;
|
|
222
|
-
res = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/signup`, {
|
|
223
|
-
headers: this.headers,
|
|
224
|
-
body: {
|
|
225
|
-
phone,
|
|
226
|
-
password,
|
|
227
|
-
data: (_b = options === null || options === void 0 ? void 0 : options.data) !== null && _b !== void 0 ? _b : {},
|
|
228
|
-
channel: (_c = options === null || options === void 0 ? void 0 : options.channel) !== null && _c !== void 0 ? _c : 'sms',
|
|
229
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
230
|
-
},
|
|
231
|
-
xform: fetch_1._sessionResponse,
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a password');
|
|
236
|
-
}
|
|
237
|
-
const { data, error } = res;
|
|
238
|
-
if (error || !data) {
|
|
239
|
-
return { data: { user: null, session: null }, error: error };
|
|
240
|
-
}
|
|
241
|
-
const session = data.session;
|
|
242
|
-
const user = data.user;
|
|
243
|
-
if (data.session) {
|
|
244
|
-
yield this._saveSession(data.session);
|
|
245
|
-
yield this._notifyAllSubscribers('SIGNED_IN', session);
|
|
246
|
-
}
|
|
247
|
-
return { data: { user, session }, error: null };
|
|
181
|
+
try {
|
|
182
|
+
await this._removeSession();
|
|
183
|
+
let res;
|
|
184
|
+
if ('email' in credentials) {
|
|
185
|
+
const { email, password, options } = credentials;
|
|
186
|
+
let codeChallenge = null;
|
|
187
|
+
let codeChallengeMethod = null;
|
|
188
|
+
if (this.flowType === 'pkce') {
|
|
189
|
+
const codeVerifier = (0, helpers_1.generatePKCEVerifier)();
|
|
190
|
+
await (0, helpers_1.setItemAsync)(this.storage, `${this.storageKey}-code-verifier`, codeVerifier);
|
|
191
|
+
codeChallenge = await (0, helpers_1.generatePKCEChallenge)(codeVerifier);
|
|
192
|
+
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256';
|
|
193
|
+
}
|
|
194
|
+
res = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/signup`, {
|
|
195
|
+
headers: this.headers,
|
|
196
|
+
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
197
|
+
body: {
|
|
198
|
+
email,
|
|
199
|
+
password,
|
|
200
|
+
data: (_a = options === null || options === void 0 ? void 0 : options.data) !== null && _a !== void 0 ? _a : {},
|
|
201
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
202
|
+
code_challenge: codeChallenge,
|
|
203
|
+
code_challenge_method: codeChallengeMethod,
|
|
204
|
+
},
|
|
205
|
+
xform: fetch_1._sessionResponse,
|
|
206
|
+
});
|
|
248
207
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
208
|
+
else if ('phone' in credentials) {
|
|
209
|
+
const { phone, password, options } = credentials;
|
|
210
|
+
res = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/signup`, {
|
|
211
|
+
headers: this.headers,
|
|
212
|
+
body: {
|
|
213
|
+
phone,
|
|
214
|
+
password,
|
|
215
|
+
data: (_b = options === null || options === void 0 ? void 0 : options.data) !== null && _b !== void 0 ? _b : {},
|
|
216
|
+
channel: (_c = options === null || options === void 0 ? void 0 : options.channel) !== null && _c !== void 0 ? _c : 'sms',
|
|
217
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
218
|
+
},
|
|
219
|
+
xform: fetch_1._sessionResponse,
|
|
220
|
+
});
|
|
254
221
|
}
|
|
255
|
-
|
|
222
|
+
else {
|
|
223
|
+
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a password');
|
|
224
|
+
}
|
|
225
|
+
const { data, error } = res;
|
|
226
|
+
if (error || !data) {
|
|
227
|
+
return { data: { user: null, session: null }, error: error };
|
|
228
|
+
}
|
|
229
|
+
const session = data.session;
|
|
230
|
+
const user = data.user;
|
|
231
|
+
if (data.session) {
|
|
232
|
+
await this._saveSession(data.session);
|
|
233
|
+
await this._notifyAllSubscribers('SIGNED_IN', session);
|
|
234
|
+
}
|
|
235
|
+
return { data: { user, session }, error: null };
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
239
|
+
return { data: { user: null, session: null }, error };
|
|
240
|
+
}
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
256
243
|
}
|
|
257
244
|
/**
|
|
258
245
|
* Log in an existing user with an email and password or phone and password.
|
|
@@ -262,146 +249,138 @@ class GoTrueClient {
|
|
|
262
249
|
* email/phone and password combination is wrong or that the account can only
|
|
263
250
|
* be accessed via social login.
|
|
264
251
|
*/
|
|
265
|
-
signInWithPassword(credentials) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
else if ('phone' in credentials) {
|
|
283
|
-
const { phone, password, options } = credentials;
|
|
284
|
-
res = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=password`, {
|
|
285
|
-
headers: this.headers,
|
|
286
|
-
body: {
|
|
287
|
-
phone,
|
|
288
|
-
password,
|
|
289
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
290
|
-
},
|
|
291
|
-
xform: fetch_1._sessionResponse,
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a password');
|
|
296
|
-
}
|
|
297
|
-
const { data, error } = res;
|
|
298
|
-
if (error) {
|
|
299
|
-
return { data: { user: null, session: null }, error };
|
|
300
|
-
}
|
|
301
|
-
else if (!data || !data.session || !data.user) {
|
|
302
|
-
return { data: { user: null, session: null }, error: new errors_1.AuthInvalidTokenResponseError() };
|
|
303
|
-
}
|
|
304
|
-
if (data.session) {
|
|
305
|
-
yield this._saveSession(data.session);
|
|
306
|
-
yield this._notifyAllSubscribers('SIGNED_IN', data.session);
|
|
307
|
-
}
|
|
308
|
-
return { data: { user: data.user, session: data.session }, error };
|
|
252
|
+
async signInWithPassword(credentials) {
|
|
253
|
+
try {
|
|
254
|
+
await this._removeSession();
|
|
255
|
+
let res;
|
|
256
|
+
if ('email' in credentials) {
|
|
257
|
+
const { email, password, options } = credentials;
|
|
258
|
+
res = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=password`, {
|
|
259
|
+
headers: this.headers,
|
|
260
|
+
body: {
|
|
261
|
+
email,
|
|
262
|
+
password,
|
|
263
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
264
|
+
},
|
|
265
|
+
xform: fetch_1._sessionResponse,
|
|
266
|
+
});
|
|
309
267
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
268
|
+
else if ('phone' in credentials) {
|
|
269
|
+
const { phone, password, options } = credentials;
|
|
270
|
+
res = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=password`, {
|
|
271
|
+
headers: this.headers,
|
|
272
|
+
body: {
|
|
273
|
+
phone,
|
|
274
|
+
password,
|
|
275
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
276
|
+
},
|
|
277
|
+
xform: fetch_1._sessionResponse,
|
|
278
|
+
});
|
|
315
279
|
}
|
|
316
|
-
|
|
280
|
+
else {
|
|
281
|
+
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a password');
|
|
282
|
+
}
|
|
283
|
+
const { data, error } = res;
|
|
284
|
+
if (error) {
|
|
285
|
+
return { data: { user: null, session: null }, error };
|
|
286
|
+
}
|
|
287
|
+
else if (!data || !data.session || !data.user) {
|
|
288
|
+
return { data: { user: null, session: null }, error: new errors_1.AuthInvalidTokenResponseError() };
|
|
289
|
+
}
|
|
290
|
+
if (data.session) {
|
|
291
|
+
await this._saveSession(data.session);
|
|
292
|
+
await this._notifyAllSubscribers('SIGNED_IN', data.session);
|
|
293
|
+
}
|
|
294
|
+
return { data: { user: data.user, session: data.session }, error };
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
298
|
+
return { data: { user: null, session: null }, error };
|
|
299
|
+
}
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
317
302
|
}
|
|
318
303
|
/**
|
|
319
304
|
* Log in an existing user via a third-party provider.
|
|
320
305
|
* This method supports the PKCE flow.
|
|
321
306
|
*/
|
|
322
|
-
signInWithOAuth(credentials) {
|
|
307
|
+
async signInWithOAuth(credentials) {
|
|
323
308
|
var _a, _b, _c, _d;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
skipBrowserRedirect: (_d = credentials.options) === null || _d === void 0 ? void 0 : _d.skipBrowserRedirect,
|
|
331
|
-
});
|
|
309
|
+
await this._removeSession();
|
|
310
|
+
return await this._handleProviderSignIn(credentials.provider, {
|
|
311
|
+
redirectTo: (_a = credentials.options) === null || _a === void 0 ? void 0 : _a.redirectTo,
|
|
312
|
+
scopes: (_b = credentials.options) === null || _b === void 0 ? void 0 : _b.scopes,
|
|
313
|
+
queryParams: (_c = credentials.options) === null || _c === void 0 ? void 0 : _c.queryParams,
|
|
314
|
+
skipBrowserRedirect: (_d = credentials.options) === null || _d === void 0 ? void 0 : _d.skipBrowserRedirect,
|
|
332
315
|
});
|
|
333
316
|
}
|
|
334
317
|
/**
|
|
335
318
|
* Log in an existing user by exchanging an Auth Code issued during the PKCE flow.
|
|
336
319
|
*/
|
|
337
|
-
exchangeCodeForSession(authCode) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
320
|
+
async exchangeCodeForSession(authCode) {
|
|
321
|
+
const codeVerifier = await (0, helpers_1.getItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
|
|
322
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=pkce`, {
|
|
323
|
+
headers: this.headers,
|
|
324
|
+
body: {
|
|
325
|
+
auth_code: authCode,
|
|
326
|
+
code_verifier: codeVerifier,
|
|
327
|
+
},
|
|
328
|
+
xform: fetch_1._sessionResponse,
|
|
329
|
+
});
|
|
330
|
+
await (0, helpers_1.removeItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
|
|
331
|
+
if (error) {
|
|
332
|
+
return { data: { user: null, session: null }, error };
|
|
333
|
+
}
|
|
334
|
+
else if (!data || !data.session || !data.user) {
|
|
335
|
+
return { data: { user: null, session: null }, error: new errors_1.AuthInvalidTokenResponseError() };
|
|
336
|
+
}
|
|
337
|
+
if (data.session) {
|
|
338
|
+
await this._saveSession(data.session);
|
|
339
|
+
await this._notifyAllSubscribers('SIGNED_IN', data.session);
|
|
340
|
+
}
|
|
341
|
+
return { data, error };
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Allows signing in with an OIDC ID token. The authentication provider used
|
|
345
|
+
* should be enabled and configured.
|
|
346
|
+
*/
|
|
347
|
+
async signInWithIdToken(credentials) {
|
|
348
|
+
await this._removeSession();
|
|
349
|
+
try {
|
|
350
|
+
const { options, provider, token, access_token, nonce } = credentials;
|
|
351
|
+
const res = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=id_token`, {
|
|
341
352
|
headers: this.headers,
|
|
342
353
|
body: {
|
|
343
|
-
|
|
344
|
-
|
|
354
|
+
provider,
|
|
355
|
+
id_token: token,
|
|
356
|
+
access_token,
|
|
357
|
+
nonce,
|
|
358
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
345
359
|
},
|
|
346
360
|
xform: fetch_1._sessionResponse,
|
|
347
361
|
});
|
|
348
|
-
|
|
362
|
+
const { data, error } = res;
|
|
349
363
|
if (error) {
|
|
350
364
|
return { data: { user: null, session: null }, error };
|
|
351
365
|
}
|
|
352
366
|
else if (!data || !data.session || !data.user) {
|
|
353
|
-
return {
|
|
367
|
+
return {
|
|
368
|
+
data: { user: null, session: null },
|
|
369
|
+
error: new errors_1.AuthInvalidTokenResponseError(),
|
|
370
|
+
};
|
|
354
371
|
}
|
|
355
372
|
if (data.session) {
|
|
356
|
-
|
|
357
|
-
|
|
373
|
+
await this._saveSession(data.session);
|
|
374
|
+
await this._notifyAllSubscribers('SIGNED_IN', data.session);
|
|
358
375
|
}
|
|
359
376
|
return { data, error };
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
* should be enabled and configured.
|
|
365
|
-
*/
|
|
366
|
-
signInWithIdToken(credentials) {
|
|
367
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
368
|
-
yield this._removeSession();
|
|
369
|
-
try {
|
|
370
|
-
const { options, provider, token, access_token, nonce } = credentials;
|
|
371
|
-
const res = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=id_token`, {
|
|
372
|
-
headers: this.headers,
|
|
373
|
-
body: {
|
|
374
|
-
provider,
|
|
375
|
-
id_token: token,
|
|
376
|
-
access_token,
|
|
377
|
-
nonce,
|
|
378
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
379
|
-
},
|
|
380
|
-
xform: fetch_1._sessionResponse,
|
|
381
|
-
});
|
|
382
|
-
const { data, error } = res;
|
|
383
|
-
if (error) {
|
|
384
|
-
return { data: { user: null, session: null }, error };
|
|
385
|
-
}
|
|
386
|
-
else if (!data || !data.session || !data.user) {
|
|
387
|
-
return {
|
|
388
|
-
data: { user: null, session: null },
|
|
389
|
-
error: new errors_1.AuthInvalidTokenResponseError(),
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
if (data.session) {
|
|
393
|
-
yield this._saveSession(data.session);
|
|
394
|
-
yield this._notifyAllSubscribers('SIGNED_IN', data.session);
|
|
395
|
-
}
|
|
396
|
-
return { data, error };
|
|
397
|
-
}
|
|
398
|
-
catch (error) {
|
|
399
|
-
if ((0, errors_1.isAuthError)(error)) {
|
|
400
|
-
return { data: { user: null, session: null }, error };
|
|
401
|
-
}
|
|
402
|
-
throw error;
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
380
|
+
return { data: { user: null, session: null }, error };
|
|
403
381
|
}
|
|
404
|
-
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
405
384
|
}
|
|
406
385
|
/**
|
|
407
386
|
* Log in a user using magiclink or a one-time password (OTP).
|
|
@@ -420,97 +399,93 @@ class GoTrueClient {
|
|
|
420
399
|
* at this time.
|
|
421
400
|
* This method supports PKCE when an email is passed.
|
|
422
401
|
*/
|
|
423
|
-
signInWithOtp(credentials) {
|
|
402
|
+
async signInWithOtp(credentials) {
|
|
424
403
|
var _a, _b, _c, _d, _e;
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return { data: { user: null, session: null }, error };
|
|
451
|
-
}
|
|
452
|
-
if ('phone' in credentials) {
|
|
453
|
-
const { phone, options } = credentials;
|
|
454
|
-
const { data, error } = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/otp`, {
|
|
455
|
-
headers: this.headers,
|
|
456
|
-
body: {
|
|
457
|
-
phone,
|
|
458
|
-
data: (_c = options === null || options === void 0 ? void 0 : options.data) !== null && _c !== void 0 ? _c : {},
|
|
459
|
-
create_user: (_d = options === null || options === void 0 ? void 0 : options.shouldCreateUser) !== null && _d !== void 0 ? _d : true,
|
|
460
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
461
|
-
channel: (_e = options === null || options === void 0 ? void 0 : options.channel) !== null && _e !== void 0 ? _e : 'sms',
|
|
462
|
-
},
|
|
463
|
-
});
|
|
464
|
-
return { data: { user: null, session: null, messageId: data === null || data === void 0 ? void 0 : data.message_id }, error };
|
|
465
|
-
}
|
|
466
|
-
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number.');
|
|
404
|
+
try {
|
|
405
|
+
await this._removeSession();
|
|
406
|
+
if ('email' in credentials) {
|
|
407
|
+
const { email, options } = credentials;
|
|
408
|
+
let codeChallenge = null;
|
|
409
|
+
let codeChallengeMethod = null;
|
|
410
|
+
if (this.flowType === 'pkce') {
|
|
411
|
+
const codeVerifier = (0, helpers_1.generatePKCEVerifier)();
|
|
412
|
+
await (0, helpers_1.setItemAsync)(this.storage, `${this.storageKey}-code-verifier`, codeVerifier);
|
|
413
|
+
codeChallenge = await (0, helpers_1.generatePKCEChallenge)(codeVerifier);
|
|
414
|
+
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256';
|
|
415
|
+
}
|
|
416
|
+
const { error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/otp`, {
|
|
417
|
+
headers: this.headers,
|
|
418
|
+
body: {
|
|
419
|
+
email,
|
|
420
|
+
data: (_a = options === null || options === void 0 ? void 0 : options.data) !== null && _a !== void 0 ? _a : {},
|
|
421
|
+
create_user: (_b = options === null || options === void 0 ? void 0 : options.shouldCreateUser) !== null && _b !== void 0 ? _b : true,
|
|
422
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
423
|
+
code_challenge: codeChallenge,
|
|
424
|
+
code_challenge_method: codeChallengeMethod,
|
|
425
|
+
},
|
|
426
|
+
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
427
|
+
});
|
|
428
|
+
return { data: { user: null, session: null }, error };
|
|
467
429
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
430
|
+
if ('phone' in credentials) {
|
|
431
|
+
const { phone, options } = credentials;
|
|
432
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/otp`, {
|
|
433
|
+
headers: this.headers,
|
|
434
|
+
body: {
|
|
435
|
+
phone,
|
|
436
|
+
data: (_c = options === null || options === void 0 ? void 0 : options.data) !== null && _c !== void 0 ? _c : {},
|
|
437
|
+
create_user: (_d = options === null || options === void 0 ? void 0 : options.shouldCreateUser) !== null && _d !== void 0 ? _d : true,
|
|
438
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
439
|
+
channel: (_e = options === null || options === void 0 ? void 0 : options.channel) !== null && _e !== void 0 ? _e : 'sms',
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
return { data: { user: null, session: null, messageId: data === null || data === void 0 ? void 0 : data.message_id }, error };
|
|
473
443
|
}
|
|
474
|
-
|
|
444
|
+
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number.');
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
448
|
+
return { data: { user: null, session: null }, error };
|
|
449
|
+
}
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
475
452
|
}
|
|
476
453
|
/**
|
|
477
454
|
* Log in a user given a User supplied OTP received via mobile.
|
|
478
455
|
*/
|
|
479
|
-
verifyOtp(params) {
|
|
456
|
+
async verifyOtp(params) {
|
|
480
457
|
var _a, _b;
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if
|
|
484
|
-
|
|
485
|
-
yield this._removeSession();
|
|
486
|
-
}
|
|
487
|
-
const { data, error } = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/verify`, {
|
|
488
|
-
headers: this.headers,
|
|
489
|
-
body: Object.assign(Object.assign({}, params), { gotrue_meta_security: { captcha_token: (_a = params.options) === null || _a === void 0 ? void 0 : _a.captchaToken } }),
|
|
490
|
-
redirectTo: (_b = params.options) === null || _b === void 0 ? void 0 : _b.redirectTo,
|
|
491
|
-
xform: fetch_1._sessionResponse,
|
|
492
|
-
});
|
|
493
|
-
if (error) {
|
|
494
|
-
throw error;
|
|
495
|
-
}
|
|
496
|
-
if (!data) {
|
|
497
|
-
throw new Error('An error occurred on token verification.');
|
|
498
|
-
}
|
|
499
|
-
const session = data.session;
|
|
500
|
-
const user = data.user;
|
|
501
|
-
if (session === null || session === void 0 ? void 0 : session.access_token) {
|
|
502
|
-
yield this._saveSession(session);
|
|
503
|
-
yield this._notifyAllSubscribers('SIGNED_IN', session);
|
|
504
|
-
}
|
|
505
|
-
return { data: { user, session }, error: null };
|
|
458
|
+
try {
|
|
459
|
+
if (params.type !== 'email_change' && params.type !== 'phone_change') {
|
|
460
|
+
// we don't want to remove the authenticated session if the user is performing an email_change or phone_change verification
|
|
461
|
+
await this._removeSession();
|
|
506
462
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
463
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/verify`, {
|
|
464
|
+
headers: this.headers,
|
|
465
|
+
body: Object.assign(Object.assign({}, params), { gotrue_meta_security: { captcha_token: (_a = params.options) === null || _a === void 0 ? void 0 : _a.captchaToken } }),
|
|
466
|
+
redirectTo: (_b = params.options) === null || _b === void 0 ? void 0 : _b.redirectTo,
|
|
467
|
+
xform: fetch_1._sessionResponse,
|
|
468
|
+
});
|
|
469
|
+
if (error) {
|
|
511
470
|
throw error;
|
|
512
471
|
}
|
|
513
|
-
|
|
472
|
+
if (!data) {
|
|
473
|
+
throw new Error('An error occurred on token verification.');
|
|
474
|
+
}
|
|
475
|
+
const session = data.session;
|
|
476
|
+
const user = data.user;
|
|
477
|
+
if (session === null || session === void 0 ? void 0 : session.access_token) {
|
|
478
|
+
await this._saveSession(session);
|
|
479
|
+
await this._notifyAllSubscribers('SIGNED_IN', session);
|
|
480
|
+
}
|
|
481
|
+
return { data: { user, session }, error: null };
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
485
|
+
return { data: { user: null, session: null }, error };
|
|
486
|
+
}
|
|
487
|
+
throw error;
|
|
488
|
+
}
|
|
514
489
|
}
|
|
515
490
|
/**
|
|
516
491
|
* Attempts a single-sign on using an enterprise Identity Provider. A
|
|
@@ -526,211 +501,201 @@ class GoTrueClient {
|
|
|
526
501
|
* If you have built an organization-specific login page, you can use the
|
|
527
502
|
* organization's SSO Identity Provider UUID directly instead.
|
|
528
503
|
*/
|
|
529
|
-
signInWithSSO(params) {
|
|
504
|
+
async signInWithSSO(params) {
|
|
530
505
|
var _a, _b, _c;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
return { data: null, error };
|
|
545
|
-
}
|
|
546
|
-
throw error;
|
|
506
|
+
try {
|
|
507
|
+
await this._removeSession();
|
|
508
|
+
return await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/sso`, {
|
|
509
|
+
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: (_b = (_a = params.options) === null || _a === void 0 ? void 0 : _a.redirectTo) !== null && _b !== void 0 ? _b : undefined }), (((_c = params === null || params === void 0 ? void 0 : params.options) === null || _c === void 0 ? void 0 : _c.captchaToken)
|
|
510
|
+
? { gotrue_meta_security: { captcha_token: params.options.captchaToken } }
|
|
511
|
+
: null)), { skip_http_redirect: true }),
|
|
512
|
+
headers: this.headers,
|
|
513
|
+
xform: fetch_1._ssoResponse,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
518
|
+
return { data: null, error };
|
|
547
519
|
}
|
|
548
|
-
|
|
520
|
+
throw error;
|
|
521
|
+
}
|
|
549
522
|
}
|
|
550
523
|
/**
|
|
551
524
|
* Sends a reauthentication OTP to the user's email or phone number.
|
|
552
525
|
* Requires the user to be signed-in.
|
|
553
526
|
*/
|
|
554
|
-
reauthenticate() {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
527
|
+
async reauthenticate() {
|
|
528
|
+
try {
|
|
529
|
+
const { data: { session }, error: sessionError, } = await this.getSession();
|
|
530
|
+
if (sessionError)
|
|
531
|
+
throw sessionError;
|
|
532
|
+
if (!session)
|
|
533
|
+
throw new errors_1.AuthSessionMissingError();
|
|
534
|
+
const { error } = await (0, fetch_1._request)(this.fetch, 'GET', `${this.url}/reauthenticate`, {
|
|
535
|
+
headers: this.headers,
|
|
536
|
+
jwt: session.access_token,
|
|
537
|
+
});
|
|
538
|
+
return { data: { user: null, session: null }, error };
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
566
542
|
return { data: { user: null, session: null }, error };
|
|
567
543
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
return { data: { user: null, session: null }, error };
|
|
571
|
-
}
|
|
572
|
-
throw error;
|
|
573
|
-
}
|
|
574
|
-
});
|
|
544
|
+
throw error;
|
|
545
|
+
}
|
|
575
546
|
}
|
|
576
547
|
/**
|
|
577
548
|
* Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP.
|
|
578
549
|
*/
|
|
579
|
-
resend(credentials) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
const endpoint = `${this.url}/resend`;
|
|
584
|
-
if ('email' in credentials) {
|
|
585
|
-
const { email, type, options } = credentials;
|
|
586
|
-
const { error } = yield (0, fetch_1._request)(this.fetch, 'POST', endpoint, {
|
|
587
|
-
headers: this.headers,
|
|
588
|
-
body: {
|
|
589
|
-
email,
|
|
590
|
-
type,
|
|
591
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
592
|
-
},
|
|
593
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
594
|
-
});
|
|
595
|
-
return { data: { user: null, session: null }, error };
|
|
596
|
-
}
|
|
597
|
-
else if ('phone' in credentials) {
|
|
598
|
-
const { phone, type, options } = credentials;
|
|
599
|
-
const { data, error } = yield (0, fetch_1._request)(this.fetch, 'POST', endpoint, {
|
|
600
|
-
headers: this.headers,
|
|
601
|
-
body: {
|
|
602
|
-
phone,
|
|
603
|
-
type,
|
|
604
|
-
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
605
|
-
},
|
|
606
|
-
});
|
|
607
|
-
return { data: { user: null, session: null, messageId: data === null || data === void 0 ? void 0 : data.message_id }, error };
|
|
608
|
-
}
|
|
609
|
-
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a type');
|
|
550
|
+
async resend(credentials) {
|
|
551
|
+
try {
|
|
552
|
+
if (credentials.type != 'email_change' && credentials.type != 'phone_change') {
|
|
553
|
+
await this._removeSession();
|
|
610
554
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
|
|
555
|
+
const endpoint = `${this.url}/resend`;
|
|
556
|
+
if ('email' in credentials) {
|
|
557
|
+
const { email, type, options } = credentials;
|
|
558
|
+
const { error } = await (0, fetch_1._request)(this.fetch, 'POST', endpoint, {
|
|
559
|
+
headers: this.headers,
|
|
560
|
+
body: {
|
|
561
|
+
email,
|
|
562
|
+
type,
|
|
563
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
564
|
+
},
|
|
565
|
+
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
566
|
+
});
|
|
567
|
+
return { data: { user: null, session: null }, error };
|
|
616
568
|
}
|
|
617
|
-
|
|
569
|
+
else if ('phone' in credentials) {
|
|
570
|
+
const { phone, type, options } = credentials;
|
|
571
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', endpoint, {
|
|
572
|
+
headers: this.headers,
|
|
573
|
+
body: {
|
|
574
|
+
phone,
|
|
575
|
+
type,
|
|
576
|
+
gotrue_meta_security: { captcha_token: options === null || options === void 0 ? void 0 : options.captchaToken },
|
|
577
|
+
},
|
|
578
|
+
});
|
|
579
|
+
return { data: { user: null, session: null, messageId: data === null || data === void 0 ? void 0 : data.message_id }, error };
|
|
580
|
+
}
|
|
581
|
+
throw new errors_1.AuthInvalidCredentialsError('You must provide either an email or phone number and a type');
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
585
|
+
return { data: { user: null, session: null }, error };
|
|
586
|
+
}
|
|
587
|
+
throw error;
|
|
588
|
+
}
|
|
618
589
|
}
|
|
619
590
|
/**
|
|
620
591
|
* Returns the session, refreshing it if necessary.
|
|
621
592
|
* The session returned can be null if the session is not detected which can happen in the event a user is not signed-in or has logged out.
|
|
622
593
|
*/
|
|
623
|
-
getSession() {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (maybeSession
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
yield this._removeSession();
|
|
641
|
-
}
|
|
594
|
+
async getSession() {
|
|
595
|
+
// make sure we've read the session from the url if there is one
|
|
596
|
+
// save to just await, as long we make sure _initialize() never throws
|
|
597
|
+
await this.initializePromise;
|
|
598
|
+
this._debug('#getSession()', 'begin');
|
|
599
|
+
try {
|
|
600
|
+
let currentSession = null;
|
|
601
|
+
if (this.persistSession) {
|
|
602
|
+
const maybeSession = await (0, helpers_1.getItemAsync)(this.storage, this.storageKey);
|
|
603
|
+
this._debug('#getSession()', 'session from storage', maybeSession);
|
|
604
|
+
if (maybeSession !== null) {
|
|
605
|
+
if (this._isValidSession(maybeSession)) {
|
|
606
|
+
currentSession = maybeSession;
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
this._debug('#getSession()', 'session from storage is not valid');
|
|
610
|
+
await this._removeSession();
|
|
642
611
|
}
|
|
643
612
|
}
|
|
644
|
-
else {
|
|
645
|
-
currentSession = this.inMemorySession;
|
|
646
|
-
this._debug('#getSession()', 'session from memory', currentSession);
|
|
647
|
-
}
|
|
648
|
-
if (!currentSession) {
|
|
649
|
-
return { data: { session: null }, error: null };
|
|
650
|
-
}
|
|
651
|
-
const hasExpired = currentSession.expires_at
|
|
652
|
-
? currentSession.expires_at <= Date.now() / 1000
|
|
653
|
-
: false;
|
|
654
|
-
this._debug('#getSession()', `session has${hasExpired ? '' : ' not'} expired`, 'expires_at', currentSession.expires_at);
|
|
655
|
-
if (!hasExpired) {
|
|
656
|
-
return { data: { session: currentSession }, error: null };
|
|
657
|
-
}
|
|
658
|
-
const { session, error } = yield this._callRefreshToken(currentSession.refresh_token);
|
|
659
|
-
if (error) {
|
|
660
|
-
return { data: { session: null }, error };
|
|
661
|
-
}
|
|
662
|
-
return { data: { session }, error: null };
|
|
663
613
|
}
|
|
664
|
-
|
|
665
|
-
this.
|
|
614
|
+
else {
|
|
615
|
+
currentSession = this.inMemorySession;
|
|
616
|
+
this._debug('#getSession()', 'session from memory', currentSession);
|
|
666
617
|
}
|
|
667
|
-
|
|
668
|
-
|
|
618
|
+
if (!currentSession) {
|
|
619
|
+
return { data: { session: null }, error: null };
|
|
620
|
+
}
|
|
621
|
+
const hasExpired = currentSession.expires_at
|
|
622
|
+
? currentSession.expires_at <= Date.now() / 1000
|
|
623
|
+
: false;
|
|
624
|
+
this._debug('#getSession()', `session has${hasExpired ? '' : ' not'} expired`, 'expires_at', currentSession.expires_at);
|
|
625
|
+
if (!hasExpired) {
|
|
626
|
+
return { data: { session: currentSession }, error: null };
|
|
627
|
+
}
|
|
628
|
+
const { session, error } = await this._callRefreshToken(currentSession.refresh_token);
|
|
629
|
+
if (error) {
|
|
630
|
+
return { data: { session: null }, error };
|
|
631
|
+
}
|
|
632
|
+
return { data: { session }, error: null };
|
|
633
|
+
}
|
|
634
|
+
finally {
|
|
635
|
+
this._debug('#getSession()', 'end');
|
|
636
|
+
}
|
|
637
|
+
}
|
|
669
638
|
/**
|
|
670
639
|
* Gets the current user details if there is an existing session.
|
|
671
640
|
* @param jwt Takes in an optional access token jwt. If no jwt is provided, getUser() will attempt to get the jwt from the current session.
|
|
672
641
|
*/
|
|
673
|
-
getUser(jwt) {
|
|
642
|
+
async getUser(jwt) {
|
|
674
643
|
var _a, _b;
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
throw error;
|
|
681
|
-
}
|
|
682
|
-
// Default to Authorization header if there is no existing session
|
|
683
|
-
jwt = (_b = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token) !== null && _b !== void 0 ? _b : undefined;
|
|
644
|
+
try {
|
|
645
|
+
if (!jwt) {
|
|
646
|
+
const { data, error } = await this.getSession();
|
|
647
|
+
if (error) {
|
|
648
|
+
throw error;
|
|
684
649
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
jwt: jwt,
|
|
688
|
-
xform: fetch_1._userResponse,
|
|
689
|
-
});
|
|
650
|
+
// Default to Authorization header if there is no existing session
|
|
651
|
+
jwt = (_b = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token) !== null && _b !== void 0 ? _b : undefined;
|
|
690
652
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
653
|
+
return await (0, fetch_1._request)(this.fetch, 'GET', `${this.url}/user`, {
|
|
654
|
+
headers: this.headers,
|
|
655
|
+
jwt: jwt,
|
|
656
|
+
xform: fetch_1._userResponse,
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
catch (error) {
|
|
660
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
661
|
+
return { data: { user: null }, error };
|
|
696
662
|
}
|
|
697
|
-
|
|
663
|
+
throw error;
|
|
664
|
+
}
|
|
698
665
|
}
|
|
699
666
|
/**
|
|
700
667
|
* Updates user data for a logged in user.
|
|
701
668
|
*/
|
|
702
|
-
updateUser(attributes, options = {}) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
throw sessionError;
|
|
708
|
-
}
|
|
709
|
-
if (!sessionData.session) {
|
|
710
|
-
throw new errors_1.AuthSessionMissingError();
|
|
711
|
-
}
|
|
712
|
-
const session = sessionData.session;
|
|
713
|
-
const { data, error: userError } = yield (0, fetch_1._request)(this.fetch, 'PUT', `${this.url}/user`, {
|
|
714
|
-
headers: this.headers,
|
|
715
|
-
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
716
|
-
body: attributes,
|
|
717
|
-
jwt: session.access_token,
|
|
718
|
-
xform: fetch_1._userResponse,
|
|
719
|
-
});
|
|
720
|
-
if (userError)
|
|
721
|
-
throw userError;
|
|
722
|
-
session.user = data.user;
|
|
723
|
-
yield this._saveSession(session);
|
|
724
|
-
yield this._notifyAllSubscribers('USER_UPDATED', session);
|
|
725
|
-
return { data: { user: session.user }, error: null };
|
|
726
|
-
}
|
|
727
|
-
catch (error) {
|
|
728
|
-
if ((0, errors_1.isAuthError)(error)) {
|
|
729
|
-
return { data: { user: null }, error };
|
|
730
|
-
}
|
|
731
|
-
throw error;
|
|
669
|
+
async updateUser(attributes, options = {}) {
|
|
670
|
+
try {
|
|
671
|
+
const { data: sessionData, error: sessionError } = await this.getSession();
|
|
672
|
+
if (sessionError) {
|
|
673
|
+
throw sessionError;
|
|
732
674
|
}
|
|
733
|
-
|
|
675
|
+
if (!sessionData.session) {
|
|
676
|
+
throw new errors_1.AuthSessionMissingError();
|
|
677
|
+
}
|
|
678
|
+
const session = sessionData.session;
|
|
679
|
+
const { data, error: userError } = await (0, fetch_1._request)(this.fetch, 'PUT', `${this.url}/user`, {
|
|
680
|
+
headers: this.headers,
|
|
681
|
+
redirectTo: options === null || options === void 0 ? void 0 : options.emailRedirectTo,
|
|
682
|
+
body: attributes,
|
|
683
|
+
jwt: session.access_token,
|
|
684
|
+
xform: fetch_1._userResponse,
|
|
685
|
+
});
|
|
686
|
+
if (userError)
|
|
687
|
+
throw userError;
|
|
688
|
+
session.user = data.user;
|
|
689
|
+
await this._saveSession(session);
|
|
690
|
+
await this._notifyAllSubscribers('USER_UPDATED', session);
|
|
691
|
+
return { data: { user: session.user }, error: null };
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
695
|
+
return { data: { user: null }, error };
|
|
696
|
+
}
|
|
697
|
+
throw error;
|
|
698
|
+
}
|
|
734
699
|
}
|
|
735
700
|
/**
|
|
736
701
|
* Decodes a JWT (without performing any validation).
|
|
@@ -743,56 +708,54 @@ class GoTrueClient {
|
|
|
743
708
|
* If the refresh token or access token in the current session is invalid, an error will be thrown.
|
|
744
709
|
* @param currentSession The current session that minimally contains an access token and refresh token.
|
|
745
710
|
*/
|
|
746
|
-
setSession(currentSession) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
return { data: { user: null, session: null }, error: error };
|
|
765
|
-
}
|
|
766
|
-
if (!refreshedSession) {
|
|
767
|
-
return { data: { user: null, session: null }, error: null };
|
|
768
|
-
}
|
|
769
|
-
session = refreshedSession;
|
|
711
|
+
async setSession(currentSession) {
|
|
712
|
+
try {
|
|
713
|
+
if (!currentSession.access_token || !currentSession.refresh_token) {
|
|
714
|
+
throw new errors_1.AuthSessionMissingError();
|
|
715
|
+
}
|
|
716
|
+
const timeNow = Date.now() / 1000;
|
|
717
|
+
let expiresAt = timeNow;
|
|
718
|
+
let hasExpired = true;
|
|
719
|
+
let session = null;
|
|
720
|
+
const payload = (0, helpers_1.decodeJWTPayload)(currentSession.access_token);
|
|
721
|
+
if (payload.exp) {
|
|
722
|
+
expiresAt = payload.exp;
|
|
723
|
+
hasExpired = expiresAt <= timeNow;
|
|
724
|
+
}
|
|
725
|
+
if (hasExpired) {
|
|
726
|
+
const { session: refreshedSession, error } = await this._callRefreshToken(currentSession.refresh_token);
|
|
727
|
+
if (error) {
|
|
728
|
+
return { data: { user: null, session: null }, error: error };
|
|
770
729
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (error) {
|
|
774
|
-
throw error;
|
|
775
|
-
}
|
|
776
|
-
session = {
|
|
777
|
-
access_token: currentSession.access_token,
|
|
778
|
-
refresh_token: currentSession.refresh_token,
|
|
779
|
-
user: data.user,
|
|
780
|
-
token_type: 'bearer',
|
|
781
|
-
expires_in: expiresAt - timeNow,
|
|
782
|
-
expires_at: expiresAt,
|
|
783
|
-
};
|
|
784
|
-
yield this._saveSession(session);
|
|
785
|
-
yield this._notifyAllSubscribers('SIGNED_IN', session);
|
|
730
|
+
if (!refreshedSession) {
|
|
731
|
+
return { data: { user: null, session: null }, error: null };
|
|
786
732
|
}
|
|
787
|
-
|
|
733
|
+
session = refreshedSession;
|
|
788
734
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
735
|
+
else {
|
|
736
|
+
const { data, error } = await this.getUser(currentSession.access_token);
|
|
737
|
+
if (error) {
|
|
738
|
+
throw error;
|
|
792
739
|
}
|
|
793
|
-
|
|
740
|
+
session = {
|
|
741
|
+
access_token: currentSession.access_token,
|
|
742
|
+
refresh_token: currentSession.refresh_token,
|
|
743
|
+
user: data.user,
|
|
744
|
+
token_type: 'bearer',
|
|
745
|
+
expires_in: expiresAt - timeNow,
|
|
746
|
+
expires_at: expiresAt,
|
|
747
|
+
};
|
|
748
|
+
await this._saveSession(session);
|
|
749
|
+
await this._notifyAllSubscribers('SIGNED_IN', session);
|
|
794
750
|
}
|
|
795
|
-
|
|
751
|
+
return { data: { user: session.user, session }, error: null };
|
|
752
|
+
}
|
|
753
|
+
catch (error) {
|
|
754
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
755
|
+
return { data: { session: null, user: null }, error };
|
|
756
|
+
}
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
796
759
|
}
|
|
797
760
|
/**
|
|
798
761
|
* Returns a new session, regardless of expiry status.
|
|
@@ -800,118 +763,114 @@ class GoTrueClient {
|
|
|
800
763
|
* If the current session's refresh token is invalid, an error will be thrown.
|
|
801
764
|
* @param currentSession The current session. If passed in, it must contain a refresh token.
|
|
802
765
|
*/
|
|
803
|
-
refreshSession(currentSession) {
|
|
766
|
+
async refreshSession(currentSession) {
|
|
804
767
|
var _a;
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
const { data, error } = yield this.getSession();
|
|
809
|
-
if (error) {
|
|
810
|
-
throw error;
|
|
811
|
-
}
|
|
812
|
-
currentSession = (_a = data.session) !== null && _a !== void 0 ? _a : undefined;
|
|
813
|
-
}
|
|
814
|
-
if (!(currentSession === null || currentSession === void 0 ? void 0 : currentSession.refresh_token)) {
|
|
815
|
-
throw new errors_1.AuthSessionMissingError();
|
|
816
|
-
}
|
|
817
|
-
const { session, error } = yield this._callRefreshToken(currentSession.refresh_token);
|
|
768
|
+
try {
|
|
769
|
+
if (!currentSession) {
|
|
770
|
+
const { data, error } = await this.getSession();
|
|
818
771
|
if (error) {
|
|
819
|
-
|
|
820
|
-
}
|
|
821
|
-
if (!session) {
|
|
822
|
-
return { data: { user: null, session: null }, error: null };
|
|
772
|
+
throw error;
|
|
823
773
|
}
|
|
824
|
-
|
|
774
|
+
currentSession = (_a = data.session) !== null && _a !== void 0 ? _a : undefined;
|
|
825
775
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return { data: { user: null, session: null }, error };
|
|
829
|
-
}
|
|
830
|
-
throw error;
|
|
776
|
+
if (!(currentSession === null || currentSession === void 0 ? void 0 : currentSession.refresh_token)) {
|
|
777
|
+
throw new errors_1.AuthSessionMissingError();
|
|
831
778
|
}
|
|
832
|
-
|
|
779
|
+
const { session, error } = await this._callRefreshToken(currentSession.refresh_token);
|
|
780
|
+
if (error) {
|
|
781
|
+
return { data: { user: null, session: null }, error: error };
|
|
782
|
+
}
|
|
783
|
+
if (!session) {
|
|
784
|
+
return { data: { user: null, session: null }, error: null };
|
|
785
|
+
}
|
|
786
|
+
return { data: { user: session.user, session }, error: null };
|
|
787
|
+
}
|
|
788
|
+
catch (error) {
|
|
789
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
790
|
+
return { data: { user: null, session: null }, error };
|
|
791
|
+
}
|
|
792
|
+
throw error;
|
|
793
|
+
}
|
|
833
794
|
}
|
|
834
795
|
/**
|
|
835
796
|
* Gets the session data from a URL string
|
|
836
797
|
*/
|
|
837
|
-
_getSessionFromUrl(isPKCEFlow) {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const { data, error } = yield this.exchangeCodeForSession(authCode);
|
|
853
|
-
if (error)
|
|
854
|
-
throw error;
|
|
855
|
-
if (!data.session)
|
|
856
|
-
throw new errors_1.AuthPKCEGrantCodeExchangeError('No session detected.');
|
|
857
|
-
let url = new URL(window.location.href);
|
|
858
|
-
url.searchParams.delete('code');
|
|
859
|
-
window.history.replaceState(window.history.state, '', url.toString());
|
|
860
|
-
return { data: { session: data.session, redirectType: null }, error: null };
|
|
861
|
-
}
|
|
862
|
-
const error_description = (0, helpers_1.getParameterByName)('error_description');
|
|
863
|
-
if (error_description) {
|
|
864
|
-
const error_code = (0, helpers_1.getParameterByName)('error_code');
|
|
865
|
-
if (!error_code)
|
|
866
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No error_code detected.');
|
|
867
|
-
const error = (0, helpers_1.getParameterByName)('error');
|
|
868
|
-
if (!error)
|
|
869
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No error detected.');
|
|
870
|
-
throw new errors_1.AuthImplicitGrantRedirectError(error_description, { error, code: error_code });
|
|
871
|
-
}
|
|
872
|
-
const provider_token = (0, helpers_1.getParameterByName)('provider_token');
|
|
873
|
-
const provider_refresh_token = (0, helpers_1.getParameterByName)('provider_refresh_token');
|
|
874
|
-
const access_token = (0, helpers_1.getParameterByName)('access_token');
|
|
875
|
-
if (!access_token)
|
|
876
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No access_token detected.');
|
|
877
|
-
const expires_in = (0, helpers_1.getParameterByName)('expires_in');
|
|
878
|
-
if (!expires_in)
|
|
879
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No expires_in detected.');
|
|
880
|
-
const refresh_token = (0, helpers_1.getParameterByName)('refresh_token');
|
|
881
|
-
if (!refresh_token)
|
|
882
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No refresh_token detected.');
|
|
883
|
-
const token_type = (0, helpers_1.getParameterByName)('token_type');
|
|
884
|
-
if (!token_type)
|
|
885
|
-
throw new errors_1.AuthImplicitGrantRedirectError('No token_type detected.');
|
|
886
|
-
const timeNow = Math.round(Date.now() / 1000);
|
|
887
|
-
const expires_at = timeNow + parseInt(expires_in);
|
|
888
|
-
const { data, error } = yield this.getUser(access_token);
|
|
798
|
+
async _getSessionFromUrl(isPKCEFlow) {
|
|
799
|
+
try {
|
|
800
|
+
if (!(0, helpers_1.isBrowser)())
|
|
801
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No browser detected.');
|
|
802
|
+
if (this.flowType === 'implicit' && !this._isImplicitGrantFlow()) {
|
|
803
|
+
throw new errors_1.AuthImplicitGrantRedirectError('Not a valid implicit grant flow url.');
|
|
804
|
+
}
|
|
805
|
+
else if (this.flowType == 'pkce' && !isPKCEFlow) {
|
|
806
|
+
throw new errors_1.AuthPKCEGrantCodeExchangeError('Not a valid PKCE flow url.');
|
|
807
|
+
}
|
|
808
|
+
if (isPKCEFlow) {
|
|
809
|
+
const authCode = (0, helpers_1.getParameterByName)('code');
|
|
810
|
+
if (!authCode)
|
|
811
|
+
throw new errors_1.AuthPKCEGrantCodeExchangeError('No code detected.');
|
|
812
|
+
const { data, error } = await this.exchangeCodeForSession(authCode);
|
|
889
813
|
if (error)
|
|
890
814
|
throw error;
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
815
|
+
if (!data.session)
|
|
816
|
+
throw new errors_1.AuthPKCEGrantCodeExchangeError('No session detected.');
|
|
817
|
+
let url = new URL(window.location.href);
|
|
818
|
+
url.searchParams.delete('code');
|
|
819
|
+
window.history.replaceState(window.history.state, '', url.toString());
|
|
820
|
+
return { data: { session: data.session, redirectType: null }, error: null };
|
|
821
|
+
}
|
|
822
|
+
const error_description = (0, helpers_1.getParameterByName)('error_description');
|
|
823
|
+
if (error_description) {
|
|
824
|
+
const error_code = (0, helpers_1.getParameterByName)('error_code');
|
|
825
|
+
if (!error_code)
|
|
826
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No error_code detected.');
|
|
827
|
+
const error = (0, helpers_1.getParameterByName)('error');
|
|
828
|
+
if (!error)
|
|
829
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No error detected.');
|
|
830
|
+
throw new errors_1.AuthImplicitGrantRedirectError(error_description, { error, code: error_code });
|
|
831
|
+
}
|
|
832
|
+
const provider_token = (0, helpers_1.getParameterByName)('provider_token');
|
|
833
|
+
const provider_refresh_token = (0, helpers_1.getParameterByName)('provider_refresh_token');
|
|
834
|
+
const access_token = (0, helpers_1.getParameterByName)('access_token');
|
|
835
|
+
if (!access_token)
|
|
836
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No access_token detected.');
|
|
837
|
+
const expires_in = (0, helpers_1.getParameterByName)('expires_in');
|
|
838
|
+
if (!expires_in)
|
|
839
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No expires_in detected.');
|
|
840
|
+
const refresh_token = (0, helpers_1.getParameterByName)('refresh_token');
|
|
841
|
+
if (!refresh_token)
|
|
842
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No refresh_token detected.');
|
|
843
|
+
const token_type = (0, helpers_1.getParameterByName)('token_type');
|
|
844
|
+
if (!token_type)
|
|
845
|
+
throw new errors_1.AuthImplicitGrantRedirectError('No token_type detected.');
|
|
846
|
+
const timeNow = Math.round(Date.now() / 1000);
|
|
847
|
+
const expires_at = timeNow + parseInt(expires_in);
|
|
848
|
+
const { data, error } = await this.getUser(access_token);
|
|
849
|
+
if (error)
|
|
912
850
|
throw error;
|
|
851
|
+
const user = data.user;
|
|
852
|
+
const session = {
|
|
853
|
+
provider_token,
|
|
854
|
+
provider_refresh_token,
|
|
855
|
+
access_token,
|
|
856
|
+
expires_in: parseInt(expires_in),
|
|
857
|
+
expires_at,
|
|
858
|
+
refresh_token,
|
|
859
|
+
token_type,
|
|
860
|
+
user,
|
|
861
|
+
};
|
|
862
|
+
const redirectType = (0, helpers_1.getParameterByName)('type');
|
|
863
|
+
// Remove tokens from URL
|
|
864
|
+
window.location.hash = '';
|
|
865
|
+
this._debug('#_getSessionFromUrl()', 'clearing window.location.hash');
|
|
866
|
+
return { data: { session, redirectType }, error: null };
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
870
|
+
return { data: { session: null, redirectType: null }, error };
|
|
913
871
|
}
|
|
914
|
-
|
|
872
|
+
throw error;
|
|
873
|
+
}
|
|
915
874
|
}
|
|
916
875
|
/**
|
|
917
876
|
* Checks if the current URL contains parameters given by an implicit oauth grant flow (https://www.rfc-editor.org/rfc/rfc6749.html#section-4.2)
|
|
@@ -924,11 +883,9 @@ class GoTrueClient {
|
|
|
924
883
|
/**
|
|
925
884
|
* Checks if the current URL and backing storage contain parameters given by a PKCE flow
|
|
926
885
|
*/
|
|
927
|
-
_isPKCEFlow() {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
return Boolean((0, helpers_1.getParameterByName)('code')) && Boolean(currentStorageContent);
|
|
931
|
-
});
|
|
886
|
+
async _isPKCEFlow() {
|
|
887
|
+
const currentStorageContent = await (0, helpers_1.getItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
|
|
888
|
+
return Boolean((0, helpers_1.getParameterByName)('code')) && Boolean(currentStorageContent);
|
|
932
889
|
}
|
|
933
890
|
/**
|
|
934
891
|
* Inside a browser context, `signOut()` will remove the logged in user from the browser session
|
|
@@ -939,31 +896,29 @@ class GoTrueClient {
|
|
|
939
896
|
*
|
|
940
897
|
* If using others scope, no `SIGNED_OUT` event is fired!
|
|
941
898
|
*/
|
|
942
|
-
signOut({ scope } = { scope: 'global' }) {
|
|
899
|
+
async signOut({ scope } = { scope: 'global' }) {
|
|
943
900
|
var _a;
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
return { error };
|
|
957
|
-
}
|
|
901
|
+
const { data, error: sessionError } = await this.getSession();
|
|
902
|
+
if (sessionError) {
|
|
903
|
+
return { error: sessionError };
|
|
904
|
+
}
|
|
905
|
+
const accessToken = (_a = data.session) === null || _a === void 0 ? void 0 : _a.access_token;
|
|
906
|
+
if (accessToken) {
|
|
907
|
+
const { error } = await this.admin.signOut(accessToken, scope);
|
|
908
|
+
if (error) {
|
|
909
|
+
// ignore 404s since user might not exist anymore
|
|
910
|
+
// ignore 401s since an invalid or expired JWT should sign out the current session
|
|
911
|
+
if (!((0, errors_1.isAuthApiError)(error) && (error.status === 404 || error.status === 401))) {
|
|
912
|
+
return { error };
|
|
958
913
|
}
|
|
959
914
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
915
|
+
}
|
|
916
|
+
if (scope !== 'others') {
|
|
917
|
+
await this._removeSession();
|
|
918
|
+
await (0, helpers_1.removeItemAsync)(this.storage, `${this.storageKey}-code-verifier`);
|
|
919
|
+
await this._notifyAllSubscribers('SIGNED_OUT', null);
|
|
920
|
+
}
|
|
921
|
+
return { error: null };
|
|
967
922
|
}
|
|
968
923
|
/**
|
|
969
924
|
* Receive a notification every time an auth event happens.
|
|
@@ -984,22 +939,20 @@ class GoTrueClient {
|
|
|
984
939
|
this._emitInitialSession(id);
|
|
985
940
|
return { data: { subscription } };
|
|
986
941
|
}
|
|
987
|
-
_emitInitialSession(id) {
|
|
942
|
+
async _emitInitialSession(id) {
|
|
988
943
|
var _a, _b;
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
});
|
|
944
|
+
try {
|
|
945
|
+
const { data: { session }, error, } = await this.getSession();
|
|
946
|
+
if (error)
|
|
947
|
+
throw error;
|
|
948
|
+
await ((_a = this.stateChangeEmitters.get(id)) === null || _a === void 0 ? void 0 : _a.callback('INITIAL_SESSION', session));
|
|
949
|
+
this._debug('INITIAL_SESSION', 'callback id', id, 'session', session);
|
|
950
|
+
}
|
|
951
|
+
catch (err) {
|
|
952
|
+
await ((_b = this.stateChangeEmitters.get(id)) === null || _b === void 0 ? void 0 : _b.callback('INITIAL_SESSION', null));
|
|
953
|
+
this._debug('INITIAL_SESSION', 'callback id', id, 'error', err);
|
|
954
|
+
console.error(err);
|
|
955
|
+
}
|
|
1003
956
|
}
|
|
1004
957
|
/**
|
|
1005
958
|
* Sends a password reset request to an email address.
|
|
@@ -1008,72 +961,68 @@ class GoTrueClient {
|
|
|
1008
961
|
* @param options.redirectTo The URL to send the user to after they click the password reset link.
|
|
1009
962
|
* @param options.captchaToken Verification token received when the user completes the captcha on the site.
|
|
1010
963
|
*/
|
|
1011
|
-
resetPasswordForEmail(email, options = {}) {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
return { data: null, error };
|
|
1036
|
-
}
|
|
1037
|
-
throw error;
|
|
964
|
+
async resetPasswordForEmail(email, options = {}) {
|
|
965
|
+
let codeChallenge = null;
|
|
966
|
+
let codeChallengeMethod = null;
|
|
967
|
+
if (this.flowType === 'pkce') {
|
|
968
|
+
const codeVerifier = (0, helpers_1.generatePKCEVerifier)();
|
|
969
|
+
await (0, helpers_1.setItemAsync)(this.storage, `${this.storageKey}-code-verifier`, codeVerifier);
|
|
970
|
+
codeChallenge = await (0, helpers_1.generatePKCEChallenge)(codeVerifier);
|
|
971
|
+
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256';
|
|
972
|
+
}
|
|
973
|
+
try {
|
|
974
|
+
return await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/recover`, {
|
|
975
|
+
body: {
|
|
976
|
+
email,
|
|
977
|
+
code_challenge: codeChallenge,
|
|
978
|
+
code_challenge_method: codeChallengeMethod,
|
|
979
|
+
gotrue_meta_security: { captcha_token: options.captchaToken },
|
|
980
|
+
},
|
|
981
|
+
headers: this.headers,
|
|
982
|
+
redirectTo: options.redirectTo,
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
987
|
+
return { data: null, error };
|
|
1038
988
|
}
|
|
1039
|
-
|
|
989
|
+
throw error;
|
|
990
|
+
}
|
|
1040
991
|
}
|
|
1041
992
|
/**
|
|
1042
993
|
* Generates a new JWT.
|
|
1043
994
|
* @param refreshToken A valid refresh token that was returned on login.
|
|
1044
995
|
*/
|
|
1045
|
-
_refreshAccessToken(refreshToken) {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
return { data: { session: null, user: null }, error };
|
|
1070
|
-
}
|
|
1071
|
-
throw error;
|
|
1072
|
-
}
|
|
1073
|
-
finally {
|
|
1074
|
-
this._debug(debugName, 'end');
|
|
996
|
+
async _refreshAccessToken(refreshToken) {
|
|
997
|
+
const debugName = `#_refreshAccessToken(${refreshToken.substring(0, 5)}...)`;
|
|
998
|
+
this._debug(debugName, 'begin');
|
|
999
|
+
try {
|
|
1000
|
+
const startedAt = Date.now();
|
|
1001
|
+
// will attempt to refresh the token with exponential backoff
|
|
1002
|
+
return await (0, helpers_1.retryable)(async (attempt) => {
|
|
1003
|
+
await (0, helpers_1.sleep)(attempt * 200); // 0, 200, 400, 800, ...
|
|
1004
|
+
this._debug(debugName, 'refreshing attempt', attempt);
|
|
1005
|
+
return await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/token?grant_type=refresh_token`, {
|
|
1006
|
+
body: { refresh_token: refreshToken },
|
|
1007
|
+
headers: this.headers,
|
|
1008
|
+
xform: fetch_1._sessionResponse,
|
|
1009
|
+
});
|
|
1010
|
+
}, (attempt, _, result) => result &&
|
|
1011
|
+
result.error &&
|
|
1012
|
+
(0, errors_1.isAuthRetryableFetchError)(result.error) &&
|
|
1013
|
+
// retryable only if the request can be sent before the backoff overflows the tick duration
|
|
1014
|
+
Date.now() + (attempt + 1) * 200 - startedAt < AUTO_REFRESH_TICK_DURATION);
|
|
1015
|
+
}
|
|
1016
|
+
catch (error) {
|
|
1017
|
+
this._debug(debugName, 'error', error);
|
|
1018
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1019
|
+
return { data: { session: null, user: null }, error };
|
|
1075
1020
|
}
|
|
1076
|
-
|
|
1021
|
+
throw error;
|
|
1022
|
+
}
|
|
1023
|
+
finally {
|
|
1024
|
+
this._debug(debugName, 'end');
|
|
1025
|
+
}
|
|
1077
1026
|
}
|
|
1078
1027
|
_isValidSession(maybeSession) {
|
|
1079
1028
|
const isValidSession = typeof maybeSession === 'object' &&
|
|
@@ -1083,172 +1032,160 @@ class GoTrueClient {
|
|
|
1083
1032
|
'expires_at' in maybeSession;
|
|
1084
1033
|
return isValidSession;
|
|
1085
1034
|
}
|
|
1086
|
-
_handleProviderSignIn(provider, options) {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
queryParams: options.queryParams,
|
|
1092
|
-
});
|
|
1093
|
-
this._debug('#_handleProviderSignIn()', 'provider', provider, 'options', options, 'url', url);
|
|
1094
|
-
// try to open on the browser
|
|
1095
|
-
if ((0, helpers_1.isBrowser)() && !options.skipBrowserRedirect) {
|
|
1096
|
-
window.location.assign(url);
|
|
1097
|
-
}
|
|
1098
|
-
return { data: { provider, url }, error: null };
|
|
1035
|
+
async _handleProviderSignIn(provider, options) {
|
|
1036
|
+
const url = await this._getUrlForProvider(provider, {
|
|
1037
|
+
redirectTo: options.redirectTo,
|
|
1038
|
+
scopes: options.scopes,
|
|
1039
|
+
queryParams: options.queryParams,
|
|
1099
1040
|
});
|
|
1041
|
+
this._debug('#_handleProviderSignIn()', 'provider', provider, 'options', options, 'url', url);
|
|
1042
|
+
// try to open on the browser
|
|
1043
|
+
if ((0, helpers_1.isBrowser)() && !options.skipBrowserRedirect) {
|
|
1044
|
+
window.location.assign(url);
|
|
1045
|
+
}
|
|
1046
|
+
return { data: { provider, url }, error: null };
|
|
1100
1047
|
}
|
|
1101
1048
|
/**
|
|
1102
1049
|
* Recovers the session from LocalStorage and refreshes
|
|
1103
1050
|
* Note: this method is async to accommodate for AsyncStorage e.g. in React native.
|
|
1104
1051
|
*/
|
|
1105
|
-
_recoverAndRefresh() {
|
|
1052
|
+
async _recoverAndRefresh() {
|
|
1106
1053
|
var _a;
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
yield this._removeSession();
|
|
1117
|
-
}
|
|
1118
|
-
return;
|
|
1054
|
+
const debugName = '#_recoverAndRefresh()';
|
|
1055
|
+
this._debug(debugName, 'begin');
|
|
1056
|
+
try {
|
|
1057
|
+
const currentSession = await (0, helpers_1.getItemAsync)(this.storage, this.storageKey);
|
|
1058
|
+
this._debug(debugName, 'session from storage', currentSession);
|
|
1059
|
+
if (!this._isValidSession(currentSession)) {
|
|
1060
|
+
this._debug(debugName, 'session is not valid');
|
|
1061
|
+
if (currentSession !== null) {
|
|
1062
|
+
await this._removeSession();
|
|
1119
1063
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
const timeNow = Math.round(Date.now() / 1000);
|
|
1067
|
+
const expiresWithMargin = ((_a = currentSession.expires_at) !== null && _a !== void 0 ? _a : Infinity) < timeNow + constants_1.EXPIRY_MARGIN;
|
|
1068
|
+
this._debug(debugName, `session has${expiresWithMargin ? '' : ' not'} expired with margin of ${constants_1.EXPIRY_MARGIN}s`);
|
|
1069
|
+
if (expiresWithMargin) {
|
|
1070
|
+
if (this.autoRefreshToken && currentSession.refresh_token) {
|
|
1071
|
+
const { error } = await this._callRefreshToken(currentSession.refresh_token);
|
|
1072
|
+
if (error) {
|
|
1073
|
+
console.error(error);
|
|
1074
|
+
if (!(0, errors_1.isAuthRetryableFetchError)(error)) {
|
|
1075
|
+
this._debug(debugName, 'refresh failed with a non-retryable error, removing the session', error);
|
|
1076
|
+
await this._removeSession();
|
|
1132
1077
|
}
|
|
1133
1078
|
}
|
|
1134
1079
|
}
|
|
1135
|
-
else {
|
|
1136
|
-
// no need to persist currentSession again, as we just loaded it from
|
|
1137
|
-
// local storage; persisting it again may overwrite a value saved by
|
|
1138
|
-
// another client with access to the same local storage
|
|
1139
|
-
yield this._notifyAllSubscribers('SIGNED_IN', currentSession);
|
|
1140
|
-
}
|
|
1141
1080
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
finally {
|
|
1148
|
-
this._debug(debugName, 'end');
|
|
1081
|
+
else {
|
|
1082
|
+
// no need to persist currentSession again, as we just loaded it from
|
|
1083
|
+
// local storage; persisting it again may overwrite a value saved by
|
|
1084
|
+
// another client with access to the same local storage
|
|
1085
|
+
await this._notifyAllSubscribers('SIGNED_IN', currentSession);
|
|
1149
1086
|
}
|
|
1150
|
-
}
|
|
1087
|
+
}
|
|
1088
|
+
catch (err) {
|
|
1089
|
+
this._debug(debugName, 'error', err);
|
|
1090
|
+
console.error(err);
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
finally {
|
|
1094
|
+
this._debug(debugName, 'end');
|
|
1095
|
+
}
|
|
1151
1096
|
}
|
|
1152
|
-
_callRefreshToken(refreshToken) {
|
|
1097
|
+
async _callRefreshToken(refreshToken) {
|
|
1153
1098
|
var _a, _b;
|
|
1154
|
-
|
|
1155
|
-
|
|
1099
|
+
if (!refreshToken) {
|
|
1100
|
+
throw new errors_1.AuthSessionMissingError();
|
|
1101
|
+
}
|
|
1102
|
+
// refreshing is already in progress
|
|
1103
|
+
if (this.refreshingDeferred) {
|
|
1104
|
+
return this.refreshingDeferred.promise;
|
|
1105
|
+
}
|
|
1106
|
+
const debugName = `#_callRefreshToken(${refreshToken.substring(0, 5)}...)`;
|
|
1107
|
+
this._debug(debugName, 'begin');
|
|
1108
|
+
try {
|
|
1109
|
+
this.refreshingDeferred = new helpers_1.Deferred();
|
|
1110
|
+
const { data, error } = await this._refreshAccessToken(refreshToken);
|
|
1111
|
+
if (error)
|
|
1112
|
+
throw error;
|
|
1113
|
+
if (!data.session)
|
|
1156
1114
|
throw new errors_1.AuthSessionMissingError();
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const {
|
|
1167
|
-
|
|
1168
|
-
throw error;
|
|
1169
|
-
if (!data.session)
|
|
1170
|
-
throw new errors_1.AuthSessionMissingError();
|
|
1171
|
-
yield this._saveSession(data.session);
|
|
1172
|
-
yield this._notifyAllSubscribers('TOKEN_REFRESHED', data.session);
|
|
1173
|
-
const result = { session: data.session, error: null };
|
|
1174
|
-
this.refreshingDeferred.resolve(result);
|
|
1115
|
+
await this._saveSession(data.session);
|
|
1116
|
+
await this._notifyAllSubscribers('TOKEN_REFRESHED', data.session);
|
|
1117
|
+
const result = { session: data.session, error: null };
|
|
1118
|
+
this.refreshingDeferred.resolve(result);
|
|
1119
|
+
return result;
|
|
1120
|
+
}
|
|
1121
|
+
catch (error) {
|
|
1122
|
+
this._debug(debugName, 'error', error);
|
|
1123
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1124
|
+
const result = { session: null, error };
|
|
1125
|
+
(_a = this.refreshingDeferred) === null || _a === void 0 ? void 0 : _a.resolve(result);
|
|
1175
1126
|
return result;
|
|
1176
1127
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
(_b = this.refreshingDeferred) === null || _b === void 0 ? void 0 : _b.reject(error);
|
|
1185
|
-
throw error;
|
|
1186
|
-
}
|
|
1187
|
-
finally {
|
|
1188
|
-
this.refreshingDeferred = null;
|
|
1189
|
-
this._debug(debugName, 'end');
|
|
1190
|
-
}
|
|
1191
|
-
});
|
|
1128
|
+
(_b = this.refreshingDeferred) === null || _b === void 0 ? void 0 : _b.reject(error);
|
|
1129
|
+
throw error;
|
|
1130
|
+
}
|
|
1131
|
+
finally {
|
|
1132
|
+
this.refreshingDeferred = null;
|
|
1133
|
+
this._debug(debugName, 'end');
|
|
1134
|
+
}
|
|
1192
1135
|
}
|
|
1193
|
-
_notifyAllSubscribers(event, session, broadcast = true) {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1136
|
+
async _notifyAllSubscribers(event, session, broadcast = true) {
|
|
1137
|
+
const debugName = `#_notifyAllSubscribers(${event})`;
|
|
1138
|
+
this._debug(debugName, 'begin', session, `broadcast = ${broadcast}`);
|
|
1139
|
+
try {
|
|
1140
|
+
if (this.broadcastChannel && broadcast) {
|
|
1141
|
+
this.broadcastChannel.postMessage({ event, session });
|
|
1142
|
+
}
|
|
1143
|
+
const errors = [];
|
|
1144
|
+
const promises = Array.from(this.stateChangeEmitters.values()).map(async (x) => {
|
|
1145
|
+
try {
|
|
1146
|
+
await x.callback(event, session);
|
|
1200
1147
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
try {
|
|
1204
|
-
yield x.callback(event, session);
|
|
1205
|
-
}
|
|
1206
|
-
catch (e) {
|
|
1207
|
-
errors.push(e);
|
|
1208
|
-
}
|
|
1209
|
-
}));
|
|
1210
|
-
yield Promise.all(promises);
|
|
1211
|
-
if (errors.length > 0) {
|
|
1212
|
-
for (let i = 0; i < errors.length; i += 1) {
|
|
1213
|
-
console.error(errors[i]);
|
|
1214
|
-
}
|
|
1215
|
-
throw errors[0];
|
|
1148
|
+
catch (e) {
|
|
1149
|
+
errors.push(e);
|
|
1216
1150
|
}
|
|
1151
|
+
});
|
|
1152
|
+
await Promise.all(promises);
|
|
1153
|
+
if (errors.length > 0) {
|
|
1154
|
+
for (let i = 0; i < errors.length; i += 1) {
|
|
1155
|
+
console.error(errors[i]);
|
|
1156
|
+
}
|
|
1157
|
+
throw errors[0];
|
|
1217
1158
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
}
|
|
1159
|
+
}
|
|
1160
|
+
finally {
|
|
1161
|
+
this._debug(debugName, 'end');
|
|
1162
|
+
}
|
|
1222
1163
|
}
|
|
1223
1164
|
/**
|
|
1224
1165
|
* set currentSession and currentUser
|
|
1225
1166
|
* process to _startAutoRefreshToken if possible
|
|
1226
1167
|
*/
|
|
1227
|
-
_saveSession(session) {
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
}
|
|
1236
|
-
});
|
|
1168
|
+
async _saveSession(session) {
|
|
1169
|
+
this._debug('#_saveSession()', session);
|
|
1170
|
+
if (!this.persistSession) {
|
|
1171
|
+
this.inMemorySession = session;
|
|
1172
|
+
}
|
|
1173
|
+
if (this.persistSession && session.expires_at) {
|
|
1174
|
+
await this._persistSession(session);
|
|
1175
|
+
}
|
|
1237
1176
|
}
|
|
1238
1177
|
_persistSession(currentSession) {
|
|
1239
1178
|
this._debug('#_persistSession()', currentSession);
|
|
1240
1179
|
return (0, helpers_1.setItemAsync)(this.storage, this.storageKey, currentSession);
|
|
1241
1180
|
}
|
|
1242
|
-
_removeSession() {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
}
|
|
1251
|
-
});
|
|
1181
|
+
async _removeSession() {
|
|
1182
|
+
this._debug('#_removeSession()');
|
|
1183
|
+
if (this.persistSession) {
|
|
1184
|
+
await (0, helpers_1.removeItemAsync)(this.storage, this.storageKey);
|
|
1185
|
+
}
|
|
1186
|
+
else {
|
|
1187
|
+
this.inMemorySession = null;
|
|
1188
|
+
}
|
|
1252
1189
|
}
|
|
1253
1190
|
/**
|
|
1254
1191
|
* Removes any registered visibilitychange callback.
|
|
@@ -1273,45 +1210,41 @@ class GoTrueClient {
|
|
|
1273
1210
|
* This is the private implementation of {@link #startAutoRefresh}. Use this
|
|
1274
1211
|
* within the library.
|
|
1275
1212
|
*/
|
|
1276
|
-
_startAutoRefresh() {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
yield this._autoRefreshTokenTick();
|
|
1300
|
-
});
|
|
1213
|
+
async _startAutoRefresh() {
|
|
1214
|
+
await this._stopAutoRefresh();
|
|
1215
|
+
this._debug('#_startAutoRefresh()');
|
|
1216
|
+
const ticker = setInterval(() => this._autoRefreshTokenTick(), AUTO_REFRESH_TICK_DURATION);
|
|
1217
|
+
this.autoRefreshTicker = ticker;
|
|
1218
|
+
if (ticker && typeof ticker === 'object' && typeof ticker.unref === 'function') {
|
|
1219
|
+
// ticker is a NodeJS Timeout object that has an `unref` method
|
|
1220
|
+
// https://nodejs.org/api/timers.html#timeoutunref
|
|
1221
|
+
// When auto refresh is used in NodeJS (like for testing) the
|
|
1222
|
+
// `setInterval` is preventing the process from being marked as
|
|
1223
|
+
// finished and tests run endlessly. This can be prevented by calling
|
|
1224
|
+
// `unref()` on the returned object.
|
|
1225
|
+
ticker.unref();
|
|
1226
|
+
// @ts-ignore
|
|
1227
|
+
}
|
|
1228
|
+
else if (typeof Deno !== 'undefined' && typeof Deno.unrefTimer === 'function') {
|
|
1229
|
+
// similar like for NodeJS, but with the Deno API
|
|
1230
|
+
// https://deno.land/api@latest?unstable&s=Deno.unrefTimer
|
|
1231
|
+
// @ts-ignore
|
|
1232
|
+
Deno.unrefTimer(ticker);
|
|
1233
|
+
}
|
|
1234
|
+
// run the tick immediately
|
|
1235
|
+
await this._autoRefreshTokenTick();
|
|
1301
1236
|
}
|
|
1302
1237
|
/**
|
|
1303
1238
|
* This is the private implementation of {@link #stopAutoRefresh}. Use this
|
|
1304
1239
|
* within the library.
|
|
1305
1240
|
*/
|
|
1306
|
-
_stopAutoRefresh() {
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
}
|
|
1314
|
-
});
|
|
1241
|
+
async _stopAutoRefresh() {
|
|
1242
|
+
this._debug('#_stopAutoRefresh()');
|
|
1243
|
+
const ticker = this.autoRefreshTicker;
|
|
1244
|
+
this.autoRefreshTicker = null;
|
|
1245
|
+
if (ticker) {
|
|
1246
|
+
clearInterval(ticker);
|
|
1247
|
+
}
|
|
1315
1248
|
}
|
|
1316
1249
|
/**
|
|
1317
1250
|
* Starts an auto-refresh process in the background. The session is checked
|
|
@@ -1335,11 +1268,9 @@ class GoTrueClient {
|
|
|
1335
1268
|
*
|
|
1336
1269
|
* {@see #stopAutoRefresh}
|
|
1337
1270
|
*/
|
|
1338
|
-
startAutoRefresh() {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
yield this._startAutoRefresh();
|
|
1342
|
-
});
|
|
1271
|
+
async startAutoRefresh() {
|
|
1272
|
+
this._removeVisibilityChangedCallback();
|
|
1273
|
+
await this._startAutoRefresh();
|
|
1343
1274
|
}
|
|
1344
1275
|
/**
|
|
1345
1276
|
* Stops an active auto refresh process running in the background (if any).
|
|
@@ -1349,94 +1280,86 @@ class GoTrueClient {
|
|
|
1349
1280
|
*
|
|
1350
1281
|
* See {@link #startAutoRefresh} for more details.
|
|
1351
1282
|
*/
|
|
1352
|
-
stopAutoRefresh() {
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
yield this._stopAutoRefresh();
|
|
1356
|
-
});
|
|
1283
|
+
async stopAutoRefresh() {
|
|
1284
|
+
this._removeVisibilityChangedCallback();
|
|
1285
|
+
await this._stopAutoRefresh();
|
|
1357
1286
|
}
|
|
1358
1287
|
/**
|
|
1359
1288
|
* Runs the auto refresh token tick.
|
|
1360
1289
|
*/
|
|
1361
|
-
_autoRefreshTokenTick() {
|
|
1362
|
-
|
|
1363
|
-
|
|
1290
|
+
async _autoRefreshTokenTick() {
|
|
1291
|
+
this._debug('#_autoRefreshTokenTick()', 'begin');
|
|
1292
|
+
try {
|
|
1293
|
+
const now = Date.now();
|
|
1364
1294
|
try {
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
this._debug('#_autoRefreshTokenTick()', 'no session');
|
|
1370
|
-
return;
|
|
1371
|
-
}
|
|
1372
|
-
// session will expire in this many ticks (or has already expired if <= 0)
|
|
1373
|
-
const expiresInTicks = Math.floor((session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION);
|
|
1374
|
-
this._debug('#_autoRefreshTokenTick()', `access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`);
|
|
1375
|
-
if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {
|
|
1376
|
-
yield this._callRefreshToken(session.refresh_token);
|
|
1377
|
-
}
|
|
1295
|
+
const { data: { session }, } = await this.getSession();
|
|
1296
|
+
if (!session || !session.refresh_token || !session.expires_at) {
|
|
1297
|
+
this._debug('#_autoRefreshTokenTick()', 'no session');
|
|
1298
|
+
return;
|
|
1378
1299
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1300
|
+
// session will expire in this many ticks (or has already expired if <= 0)
|
|
1301
|
+
const expiresInTicks = Math.floor((session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION);
|
|
1302
|
+
this._debug('#_autoRefreshTokenTick()', `access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`);
|
|
1303
|
+
if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {
|
|
1304
|
+
await this._callRefreshToken(session.refresh_token);
|
|
1381
1305
|
}
|
|
1382
1306
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1307
|
+
catch (e) {
|
|
1308
|
+
console.error('Auto refresh tick failed with error. This is likely a transient error.', e);
|
|
1385
1309
|
}
|
|
1386
|
-
}
|
|
1310
|
+
}
|
|
1311
|
+
finally {
|
|
1312
|
+
this._debug('#_autoRefreshTokenTick()', 'end');
|
|
1313
|
+
}
|
|
1387
1314
|
}
|
|
1388
1315
|
/**
|
|
1389
1316
|
* Registers callbacks on the browser / platform, which in-turn run
|
|
1390
1317
|
* algorithms when the browser window/tab are in foreground. On non-browser
|
|
1391
1318
|
* platforms it assumes always foreground.
|
|
1392
1319
|
*/
|
|
1393
|
-
_handleVisibilityChange() {
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1320
|
+
async _handleVisibilityChange() {
|
|
1321
|
+
this._debug('#_handleVisibilityChange()');
|
|
1322
|
+
if (!(0, helpers_1.isBrowser)() || !(window === null || window === void 0 ? void 0 : window.addEventListener)) {
|
|
1323
|
+
if (this.autoRefreshToken) {
|
|
1324
|
+
// in non-browser environments the refresh token ticker runs always
|
|
1325
|
+
this.startAutoRefresh();
|
|
1326
|
+
}
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
try {
|
|
1330
|
+
this.visibilityChangedCallback = async () => await this._onVisibilityChanged(false);
|
|
1331
|
+
window === null || window === void 0 ? void 0 : window.addEventListener('visibilitychange', this.visibilityChangedCallback);
|
|
1332
|
+
// now immediately call the visbility changed callback to setup with the
|
|
1333
|
+
// current visbility state
|
|
1334
|
+
await this._onVisibilityChanged(true); // initial call
|
|
1335
|
+
}
|
|
1336
|
+
catch (error) {
|
|
1337
|
+
console.error('_handleVisibilityChange', error);
|
|
1338
|
+
}
|
|
1414
1339
|
}
|
|
1415
1340
|
/**
|
|
1416
1341
|
* Callback registered with `window.addEventListener('visibilitychange')`.
|
|
1417
1342
|
*/
|
|
1418
|
-
_onVisibilityChanged(isInitial) {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
if (
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
this._startAutoRefresh();
|
|
1432
|
-
}
|
|
1343
|
+
async _onVisibilityChanged(isInitial) {
|
|
1344
|
+
this._debug(`#_onVisibilityChanged(${isInitial})`, 'visibilityState', document.visibilityState);
|
|
1345
|
+
if (document.visibilityState === 'visible') {
|
|
1346
|
+
if (!isInitial) {
|
|
1347
|
+
// initial visibility change setup is handled in another flow under #initialize()
|
|
1348
|
+
await this.initializePromise;
|
|
1349
|
+
await this._recoverAndRefresh();
|
|
1350
|
+
this._debug('#_onVisibilityChanged()', 'finished waiting for initialize, _recoverAndRefresh');
|
|
1351
|
+
}
|
|
1352
|
+
if (this.autoRefreshToken) {
|
|
1353
|
+
// in browser environments the refresh token ticker runs only on focused tabs
|
|
1354
|
+
// which prevents race conditions
|
|
1355
|
+
this._startAutoRefresh();
|
|
1433
1356
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1357
|
+
}
|
|
1358
|
+
else if (document.visibilityState === 'hidden') {
|
|
1359
|
+
if (this.autoRefreshToken) {
|
|
1360
|
+
this._stopAutoRefresh();
|
|
1438
1361
|
}
|
|
1439
|
-
}
|
|
1362
|
+
}
|
|
1440
1363
|
}
|
|
1441
1364
|
/**
|
|
1442
1365
|
* Generates the relevant login URL for a third-party provider.
|
|
@@ -1444,213 +1367,197 @@ class GoTrueClient {
|
|
|
1444
1367
|
* @param options.scopes A space-separated list of scopes granted to the OAuth application.
|
|
1445
1368
|
* @param options.queryParams An object of key-value pairs containing query parameters granted to the OAuth application.
|
|
1446
1369
|
*/
|
|
1447
|
-
_getUrlForProvider(provider, options) {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
return `${this.url}/authorize?${urlParams.join('&')}`;
|
|
1473
|
-
});
|
|
1370
|
+
async _getUrlForProvider(provider, options) {
|
|
1371
|
+
const urlParams = [`provider=${encodeURIComponent(provider)}`];
|
|
1372
|
+
if (options === null || options === void 0 ? void 0 : options.redirectTo) {
|
|
1373
|
+
urlParams.push(`redirect_to=${encodeURIComponent(options.redirectTo)}`);
|
|
1374
|
+
}
|
|
1375
|
+
if (options === null || options === void 0 ? void 0 : options.scopes) {
|
|
1376
|
+
urlParams.push(`scopes=${encodeURIComponent(options.scopes)}`);
|
|
1377
|
+
}
|
|
1378
|
+
if (this.flowType === 'pkce') {
|
|
1379
|
+
const codeVerifier = (0, helpers_1.generatePKCEVerifier)();
|
|
1380
|
+
await (0, helpers_1.setItemAsync)(this.storage, `${this.storageKey}-code-verifier`, codeVerifier);
|
|
1381
|
+
const codeChallenge = await (0, helpers_1.generatePKCEChallenge)(codeVerifier);
|
|
1382
|
+
const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256';
|
|
1383
|
+
this._debug('PKCE', 'code verifier', `${codeVerifier.substring(0, 5)}...`, 'code challenge', codeChallenge, 'method', codeChallengeMethod);
|
|
1384
|
+
const flowParams = new URLSearchParams({
|
|
1385
|
+
code_challenge: `${encodeURIComponent(codeChallenge)}`,
|
|
1386
|
+
code_challenge_method: `${encodeURIComponent(codeChallengeMethod)}`,
|
|
1387
|
+
});
|
|
1388
|
+
urlParams.push(flowParams.toString());
|
|
1389
|
+
}
|
|
1390
|
+
if (options === null || options === void 0 ? void 0 : options.queryParams) {
|
|
1391
|
+
const query = new URLSearchParams(options.queryParams);
|
|
1392
|
+
urlParams.push(query.toString());
|
|
1393
|
+
}
|
|
1394
|
+
return `${this.url}/authorize?${urlParams.join('&')}`;
|
|
1474
1395
|
}
|
|
1475
|
-
_unenroll(params) {
|
|
1396
|
+
async _unenroll(params) {
|
|
1476
1397
|
var _a;
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
return { data: null, error: sessionError };
|
|
1482
|
-
}
|
|
1483
|
-
return yield (0, fetch_1._request)(this.fetch, 'DELETE', `${this.url}/factors/${params.factorId}`, {
|
|
1484
|
-
headers: this.headers,
|
|
1485
|
-
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1486
|
-
});
|
|
1398
|
+
try {
|
|
1399
|
+
const { data: sessionData, error: sessionError } = await this.getSession();
|
|
1400
|
+
if (sessionError) {
|
|
1401
|
+
return { data: null, error: sessionError };
|
|
1487
1402
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1403
|
+
return await (0, fetch_1._request)(this.fetch, 'DELETE', `${this.url}/factors/${params.factorId}`, {
|
|
1404
|
+
headers: this.headers,
|
|
1405
|
+
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
catch (error) {
|
|
1409
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1410
|
+
return { data: null, error };
|
|
1493
1411
|
}
|
|
1494
|
-
|
|
1412
|
+
throw error;
|
|
1413
|
+
}
|
|
1495
1414
|
}
|
|
1496
1415
|
/**
|
|
1497
1416
|
* {@see GoTrueMFAApi#enroll}
|
|
1498
1417
|
*/
|
|
1499
|
-
_enroll(params) {
|
|
1418
|
+
async _enroll(params) {
|
|
1500
1419
|
var _a, _b;
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
return { data: null, error: sessionError };
|
|
1506
|
-
}
|
|
1507
|
-
const { data, error } = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors`, {
|
|
1508
|
-
body: {
|
|
1509
|
-
friendly_name: params.friendlyName,
|
|
1510
|
-
factor_type: params.factorType,
|
|
1511
|
-
issuer: params.issuer,
|
|
1512
|
-
},
|
|
1513
|
-
headers: this.headers,
|
|
1514
|
-
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1515
|
-
});
|
|
1516
|
-
if (error) {
|
|
1517
|
-
return { data: null, error };
|
|
1518
|
-
}
|
|
1519
|
-
if ((_b = data === null || data === void 0 ? void 0 : data.totp) === null || _b === void 0 ? void 0 : _b.qr_code) {
|
|
1520
|
-
data.totp.qr_code = `data:image/svg+xml;utf-8,${data.totp.qr_code}`;
|
|
1521
|
-
}
|
|
1522
|
-
return { data, error: null };
|
|
1420
|
+
try {
|
|
1421
|
+
const { data: sessionData, error: sessionError } = await this.getSession();
|
|
1422
|
+
if (sessionError) {
|
|
1423
|
+
return { data: null, error: sessionError };
|
|
1523
1424
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1425
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors`, {
|
|
1426
|
+
body: {
|
|
1427
|
+
friendly_name: params.friendlyName,
|
|
1428
|
+
factor_type: params.factorType,
|
|
1429
|
+
issuer: params.issuer,
|
|
1430
|
+
},
|
|
1431
|
+
headers: this.headers,
|
|
1432
|
+
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1433
|
+
});
|
|
1434
|
+
if (error) {
|
|
1435
|
+
return { data: null, error };
|
|
1529
1436
|
}
|
|
1530
|
-
|
|
1437
|
+
if ((_b = data === null || data === void 0 ? void 0 : data.totp) === null || _b === void 0 ? void 0 : _b.qr_code) {
|
|
1438
|
+
data.totp.qr_code = `data:image/svg+xml;utf-8,${data.totp.qr_code}`;
|
|
1439
|
+
}
|
|
1440
|
+
return { data, error: null };
|
|
1441
|
+
}
|
|
1442
|
+
catch (error) {
|
|
1443
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1444
|
+
return { data: null, error };
|
|
1445
|
+
}
|
|
1446
|
+
throw error;
|
|
1447
|
+
}
|
|
1531
1448
|
}
|
|
1532
1449
|
/**
|
|
1533
1450
|
* {@see GoTrueMFAApi#verify}
|
|
1534
1451
|
*/
|
|
1535
|
-
_verify(params) {
|
|
1452
|
+
async _verify(params) {
|
|
1536
1453
|
var _a;
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
return { data: null, error: sessionError };
|
|
1542
|
-
}
|
|
1543
|
-
const { data, error } = yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors/${params.factorId}/verify`, {
|
|
1544
|
-
body: { code: params.code, challenge_id: params.challengeId },
|
|
1545
|
-
headers: this.headers,
|
|
1546
|
-
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1547
|
-
});
|
|
1548
|
-
if (error) {
|
|
1549
|
-
return { data: null, error };
|
|
1550
|
-
}
|
|
1551
|
-
yield this._saveSession(Object.assign({ expires_at: Math.round(Date.now() / 1000) + data.expires_in }, data));
|
|
1552
|
-
yield this._notifyAllSubscribers('MFA_CHALLENGE_VERIFIED', data);
|
|
1553
|
-
return { data, error };
|
|
1454
|
+
try {
|
|
1455
|
+
const { data: sessionData, error: sessionError } = await this.getSession();
|
|
1456
|
+
if (sessionError) {
|
|
1457
|
+
return { data: null, error: sessionError };
|
|
1554
1458
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1459
|
+
const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors/${params.factorId}/verify`, {
|
|
1460
|
+
body: { code: params.code, challenge_id: params.challengeId },
|
|
1461
|
+
headers: this.headers,
|
|
1462
|
+
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1463
|
+
});
|
|
1464
|
+
if (error) {
|
|
1465
|
+
return { data: null, error };
|
|
1560
1466
|
}
|
|
1561
|
-
|
|
1467
|
+
await this._saveSession(Object.assign({ expires_at: Math.round(Date.now() / 1000) + data.expires_in }, data));
|
|
1468
|
+
await this._notifyAllSubscribers('MFA_CHALLENGE_VERIFIED', data);
|
|
1469
|
+
return { data, error };
|
|
1470
|
+
}
|
|
1471
|
+
catch (error) {
|
|
1472
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1473
|
+
return { data: null, error };
|
|
1474
|
+
}
|
|
1475
|
+
throw error;
|
|
1476
|
+
}
|
|
1562
1477
|
}
|
|
1563
1478
|
/**
|
|
1564
1479
|
* {@see GoTrueMFAApi#challenge}
|
|
1565
1480
|
*/
|
|
1566
|
-
_challenge(params) {
|
|
1481
|
+
async _challenge(params) {
|
|
1567
1482
|
var _a;
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
return { data: null, error: sessionError };
|
|
1573
|
-
}
|
|
1574
|
-
return yield (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors/${params.factorId}/challenge`, {
|
|
1575
|
-
headers: this.headers,
|
|
1576
|
-
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1577
|
-
});
|
|
1483
|
+
try {
|
|
1484
|
+
const { data: sessionData, error: sessionError } = await this.getSession();
|
|
1485
|
+
if (sessionError) {
|
|
1486
|
+
return { data: null, error: sessionError };
|
|
1578
1487
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1488
|
+
return await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/factors/${params.factorId}/challenge`, {
|
|
1489
|
+
headers: this.headers,
|
|
1490
|
+
jwt: (_a = sessionData === null || sessionData === void 0 ? void 0 : sessionData.session) === null || _a === void 0 ? void 0 : _a.access_token,
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
catch (error) {
|
|
1494
|
+
if ((0, errors_1.isAuthError)(error)) {
|
|
1495
|
+
return { data: null, error };
|
|
1584
1496
|
}
|
|
1585
|
-
|
|
1497
|
+
throw error;
|
|
1498
|
+
}
|
|
1586
1499
|
}
|
|
1587
1500
|
/**
|
|
1588
1501
|
* {@see GoTrueMFAApi#challengeAndVerify}
|
|
1589
1502
|
*/
|
|
1590
|
-
_challengeAndVerify(params) {
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
code: params.code,
|
|
1602
|
-
});
|
|
1503
|
+
async _challengeAndVerify(params) {
|
|
1504
|
+
const { data: challengeData, error: challengeError } = await this._challenge({
|
|
1505
|
+
factorId: params.factorId,
|
|
1506
|
+
});
|
|
1507
|
+
if (challengeError) {
|
|
1508
|
+
return { data: null, error: challengeError };
|
|
1509
|
+
}
|
|
1510
|
+
return await this._verify({
|
|
1511
|
+
factorId: params.factorId,
|
|
1512
|
+
challengeId: challengeData.id,
|
|
1513
|
+
code: params.code,
|
|
1603
1514
|
});
|
|
1604
1515
|
}
|
|
1605
1516
|
/**
|
|
1606
1517
|
* {@see GoTrueMFAApi#listFactors}
|
|
1607
1518
|
*/
|
|
1608
|
-
_listFactors() {
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
};
|
|
1623
|
-
});
|
|
1519
|
+
async _listFactors() {
|
|
1520
|
+
const { data: { user }, error: userError, } = await this.getUser();
|
|
1521
|
+
if (userError) {
|
|
1522
|
+
return { data: null, error: userError };
|
|
1523
|
+
}
|
|
1524
|
+
const factors = (user === null || user === void 0 ? void 0 : user.factors) || [];
|
|
1525
|
+
const totp = factors.filter((factor) => factor.factor_type === 'totp' && factor.status === 'verified');
|
|
1526
|
+
return {
|
|
1527
|
+
data: {
|
|
1528
|
+
all: factors,
|
|
1529
|
+
totp,
|
|
1530
|
+
},
|
|
1531
|
+
error: null,
|
|
1532
|
+
};
|
|
1624
1533
|
}
|
|
1625
1534
|
/**
|
|
1626
1535
|
* {@see GoTrueMFAApi#getAuthenticatorAssuranceLevel}
|
|
1627
1536
|
*/
|
|
1628
|
-
_getAuthenticatorAssuranceLevel() {
|
|
1537
|
+
async _getAuthenticatorAssuranceLevel() {
|
|
1629
1538
|
var _a, _b;
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
return { data: { currentLevel, nextLevel, currentAuthenticationMethods }, error: null };
|
|
1653
|
-
});
|
|
1539
|
+
const { data: { session }, error: sessionError, } = await this.getSession();
|
|
1540
|
+
if (sessionError) {
|
|
1541
|
+
return { data: null, error: sessionError };
|
|
1542
|
+
}
|
|
1543
|
+
if (!session) {
|
|
1544
|
+
return {
|
|
1545
|
+
data: { currentLevel: null, nextLevel: null, currentAuthenticationMethods: [] },
|
|
1546
|
+
error: null,
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
const payload = this._decodeJWT(session.access_token);
|
|
1550
|
+
let currentLevel = null;
|
|
1551
|
+
if (payload.aal) {
|
|
1552
|
+
currentLevel = payload.aal;
|
|
1553
|
+
}
|
|
1554
|
+
let nextLevel = currentLevel;
|
|
1555
|
+
const verifiedFactors = (_b = (_a = session.user.factors) === null || _a === void 0 ? void 0 : _a.filter((factor) => factor.status === 'verified')) !== null && _b !== void 0 ? _b : [];
|
|
1556
|
+
if (verifiedFactors.length > 0) {
|
|
1557
|
+
nextLevel = 'aal2';
|
|
1558
|
+
}
|
|
1559
|
+
const currentAuthenticationMethods = payload.amr || [];
|
|
1560
|
+
return { data: { currentLevel, nextLevel, currentAuthenticationMethods }, error: null };
|
|
1654
1561
|
}
|
|
1655
1562
|
}
|
|
1656
1563
|
exports.default = GoTrueClient;
|