@supabase/gotrue-js 2.16.0 → 2.18.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/GoTrueClient.d.ts +5 -0
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +69 -25
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/helpers.d.ts +2 -0
- package/dist/main/lib/helpers.d.ts.map +1 -1
- package/dist/main/lib/helpers.js +47 -1
- package/dist/main/lib/helpers.js.map +1 -1
- package/dist/main/lib/types.d.ts +3 -0
- package/dist/main/lib/types.d.ts.map +1 -1
- package/dist/main/lib/version.d.ts +1 -1
- package/dist/main/lib/version.js +1 -1
- package/dist/module/GoTrueClient.d.ts +5 -0
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +70 -26
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/helpers.d.ts +2 -0
- package/dist/module/lib/helpers.d.ts.map +1 -1
- package/dist/module/lib/helpers.js +41 -0
- package/dist/module/lib/helpers.js.map +1 -1
- package/dist/module/lib/types.d.ts +3 -0
- package/dist/module/lib/types.d.ts.map +1 -1
- package/dist/module/lib/version.d.ts +1 -1
- package/dist/module/lib/version.js +1 -1
- package/package.json +4 -2
- package/src/GoTrueClient.ts +57 -6
- package/src/lib/helpers.ts +42 -1
- package/src/lib/types.ts +3 -0
- package/src/lib/version.ts +1 -1
package/src/GoTrueClient.ts
CHANGED
|
@@ -23,9 +23,12 @@ import {
|
|
|
23
23
|
uuid,
|
|
24
24
|
retryable,
|
|
25
25
|
sleep,
|
|
26
|
+
generatePKCEVerifier,
|
|
27
|
+
generatePKCEChallenge,
|
|
26
28
|
} from './lib/helpers'
|
|
27
29
|
import localStorageAdapter from './lib/local-storage'
|
|
28
30
|
import { polyfillGlobalThis } from './lib/polyfills'
|
|
31
|
+
|
|
29
32
|
import type {
|
|
30
33
|
AuthChangeEvent,
|
|
31
34
|
AuthResponse,
|
|
@@ -63,6 +66,7 @@ import type {
|
|
|
63
66
|
AuthenticatorAssuranceLevels,
|
|
64
67
|
Factor,
|
|
65
68
|
MFAChallengeAndVerifyParams,
|
|
69
|
+
OAuthFlowType,
|
|
66
70
|
} from './lib/types'
|
|
67
71
|
|
|
68
72
|
polyfillGlobalThis() // Make "globalThis" available
|
|
@@ -220,9 +224,10 @@ export default class GoTrueClient {
|
|
|
220
224
|
await this._saveSession(session)
|
|
221
225
|
|
|
222
226
|
setTimeout(() => {
|
|
223
|
-
this._notifyAllSubscribers('SIGNED_IN', session)
|
|
224
227
|
if (redirectType === 'recovery') {
|
|
225
228
|
this._notifyAllSubscribers('PASSWORD_RECOVERY', session)
|
|
229
|
+
} else {
|
|
230
|
+
this._notifyAllSubscribers('SIGNED_IN', session)
|
|
226
231
|
}
|
|
227
232
|
}, 0)
|
|
228
233
|
|
|
@@ -378,14 +383,43 @@ export default class GoTrueClient {
|
|
|
378
383
|
*/
|
|
379
384
|
async signInWithOAuth(credentials: SignInWithOAuthCredentials): Promise<OAuthResponse> {
|
|
380
385
|
await this._removeSession()
|
|
381
|
-
|
|
386
|
+
|
|
387
|
+
return await this._handleProviderSignIn(credentials.provider, {
|
|
382
388
|
redirectTo: credentials.options?.redirectTo,
|
|
383
389
|
scopes: credentials.options?.scopes,
|
|
384
390
|
queryParams: credentials.options?.queryParams,
|
|
385
391
|
skipBrowserRedirect: credentials.options?.skipBrowserRedirect,
|
|
392
|
+
flowType: credentials.options?.flowType ?? 'implicit',
|
|
386
393
|
})
|
|
387
394
|
}
|
|
388
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Log in an existing user via a third-party provider.
|
|
398
|
+
*/
|
|
399
|
+
async exchangeCodeForSession(authCode: string): Promise<AuthResponse> {
|
|
400
|
+
const codeVerifier = await getItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`)
|
|
401
|
+
const { data, error } = await _request(
|
|
402
|
+
this.fetch,
|
|
403
|
+
'POST',
|
|
404
|
+
`${this.url}/token?grant_type=oauth_pkce`,
|
|
405
|
+
{
|
|
406
|
+
headers: this.headers,
|
|
407
|
+
body: {
|
|
408
|
+
auth_code: authCode,
|
|
409
|
+
code_verifier: codeVerifier,
|
|
410
|
+
},
|
|
411
|
+
xform: _sessionResponse,
|
|
412
|
+
}
|
|
413
|
+
)
|
|
414
|
+
await removeItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`)
|
|
415
|
+
if (error || !data) return { data: { user: null, session: null }, error }
|
|
416
|
+
if (data.session) {
|
|
417
|
+
await this._saveSession(data.session)
|
|
418
|
+
this._notifyAllSubscribers('SIGNED_IN', data.session)
|
|
419
|
+
}
|
|
420
|
+
return { data, error }
|
|
421
|
+
}
|
|
422
|
+
|
|
389
423
|
/**
|
|
390
424
|
* Allows signing in with an ID token issued by certain supported providers.
|
|
391
425
|
* The ID token is verified for validity and a new session is established.
|
|
@@ -1040,24 +1074,27 @@ export default class GoTrueClient {
|
|
|
1040
1074
|
return isValidSession
|
|
1041
1075
|
}
|
|
1042
1076
|
|
|
1043
|
-
private _handleProviderSignIn(
|
|
1077
|
+
private async _handleProviderSignIn(
|
|
1044
1078
|
provider: Provider,
|
|
1045
1079
|
options: {
|
|
1046
1080
|
redirectTo?: string
|
|
1047
1081
|
scopes?: string
|
|
1048
1082
|
queryParams?: { [key: string]: string }
|
|
1049
1083
|
skipBrowserRedirect?: boolean
|
|
1050
|
-
|
|
1084
|
+
flowType: OAuthFlowType
|
|
1085
|
+
}
|
|
1051
1086
|
) {
|
|
1052
|
-
const url: string = this._getUrlForProvider(provider, {
|
|
1087
|
+
const url: string = await this._getUrlForProvider(provider, {
|
|
1053
1088
|
redirectTo: options.redirectTo,
|
|
1054
1089
|
scopes: options.scopes,
|
|
1055
1090
|
queryParams: options.queryParams,
|
|
1091
|
+
flowType: options.flowType,
|
|
1056
1092
|
})
|
|
1057
1093
|
// try to open on the browser
|
|
1058
1094
|
if (isBrowser() && !options.skipBrowserRedirect) {
|
|
1059
1095
|
window.location.assign(url)
|
|
1060
1096
|
}
|
|
1097
|
+
|
|
1061
1098
|
return { data: { provider, url }, error: null }
|
|
1062
1099
|
}
|
|
1063
1100
|
|
|
@@ -1355,13 +1392,15 @@ export default class GoTrueClient {
|
|
|
1355
1392
|
* @param options.redirectTo A URL or mobile address to send the user to after they are confirmed.
|
|
1356
1393
|
* @param options.scopes A space-separated list of scopes granted to the OAuth application.
|
|
1357
1394
|
* @param options.queryParams An object of key-value pairs containing query parameters granted to the OAuth application.
|
|
1395
|
+
* @param options.flowType OAuth flow to use - defaults to implicit flow. PKCE is recommended for mobile and server-side applications.
|
|
1358
1396
|
*/
|
|
1359
|
-
private _getUrlForProvider(
|
|
1397
|
+
private async _getUrlForProvider(
|
|
1360
1398
|
provider: Provider,
|
|
1361
1399
|
options: {
|
|
1362
1400
|
redirectTo?: string
|
|
1363
1401
|
scopes?: string
|
|
1364
1402
|
queryParams?: { [key: string]: string }
|
|
1403
|
+
flowType: OAuthFlowType
|
|
1365
1404
|
}
|
|
1366
1405
|
) {
|
|
1367
1406
|
const urlParams: string[] = [`provider=${encodeURIComponent(provider)}`]
|
|
@@ -1371,10 +1410,22 @@ export default class GoTrueClient {
|
|
|
1371
1410
|
if (options?.scopes) {
|
|
1372
1411
|
urlParams.push(`scopes=${encodeURIComponent(options.scopes)}`)
|
|
1373
1412
|
}
|
|
1413
|
+
if (options?.flowType === 'pkce') {
|
|
1414
|
+
const codeVerifier = generatePKCEVerifier()
|
|
1415
|
+
await setItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`, codeVerifier)
|
|
1416
|
+
const codeChallenge = await generatePKCEChallenge(codeVerifier)
|
|
1417
|
+
const flowParams = new URLSearchParams({
|
|
1418
|
+
flow_type: `${encodeURIComponent(options.flowType)}`,
|
|
1419
|
+
code_challenge: `${encodeURIComponent(codeChallenge)}`,
|
|
1420
|
+
code_challenge_method: `${encodeURIComponent('s256')}`,
|
|
1421
|
+
})
|
|
1422
|
+
urlParams.push(flowParams.toString())
|
|
1423
|
+
}
|
|
1374
1424
|
if (options?.queryParams) {
|
|
1375
1425
|
const query = new URLSearchParams(options.queryParams)
|
|
1376
1426
|
urlParams.push(query.toString())
|
|
1377
1427
|
}
|
|
1428
|
+
|
|
1378
1429
|
return `${this.url}/authorize?${urlParams.join('&')}`
|
|
1379
1430
|
}
|
|
1380
1431
|
|
package/src/lib/helpers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SupportedStorage } from './types'
|
|
2
|
-
|
|
2
|
+
import sha256CryptoJS from 'crypto-js/sha256'
|
|
3
3
|
export function expiresAt(expiresIn: number) {
|
|
4
4
|
const timeNow = Math.round(Date.now() / 1000)
|
|
5
5
|
return timeNow + expiresIn
|
|
@@ -236,3 +236,44 @@ export function retryable<T>(
|
|
|
236
236
|
|
|
237
237
|
return promise
|
|
238
238
|
}
|
|
239
|
+
|
|
240
|
+
function dec2hex(dec: number) {
|
|
241
|
+
return ('0' + dec.toString(16)).substr(-2)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Functions below taken from: https://stackoverflow.com/questions/63309409/creating-a-code-verifier-and-challenge-for-pkce-auth-on-spotify-api-in-reactjs
|
|
245
|
+
export function generatePKCEVerifier() {
|
|
246
|
+
const verifierLength = 56
|
|
247
|
+
const array = new Uint32Array(verifierLength)
|
|
248
|
+
if (!isBrowser()) {
|
|
249
|
+
for (let i = 0; i < verifierLength; i++) {
|
|
250
|
+
array[i] = Math.floor(Math.random() * 256)
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
window.crypto.getRandomValues(array)
|
|
254
|
+
}
|
|
255
|
+
return Array.from(array, dec2hex).join('')
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function sha256(randomString: string) {
|
|
259
|
+
const encoder = new TextEncoder()
|
|
260
|
+
const encodedData = encoder.encode(randomString)
|
|
261
|
+
if (!isBrowser()) {
|
|
262
|
+
return sha256CryptoJS(randomString).toString()
|
|
263
|
+
}
|
|
264
|
+
const hash = await window.crypto.subtle.digest('SHA-256', encodedData)
|
|
265
|
+
const bytes = new Uint8Array(hash)
|
|
266
|
+
|
|
267
|
+
return Array.from(bytes)
|
|
268
|
+
.map((c) => String.fromCharCode(c))
|
|
269
|
+
.join('')
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function base64urlencode(str: string) {
|
|
273
|
+
return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export async function generatePKCEChallenge(verifier: string) {
|
|
277
|
+
const hashed = await sha256(verifier)
|
|
278
|
+
return base64urlencode(hashed)
|
|
279
|
+
}
|
package/src/lib/types.ts
CHANGED
|
@@ -429,6 +429,7 @@ export type SignInWithPasswordlessCredentials =
|
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
+
export type OAuthFlowType = 'implicit' | 'pkce'
|
|
432
433
|
export type SignInWithOAuthCredentials = {
|
|
433
434
|
/** One of the providers supported by GoTrue. */
|
|
434
435
|
provider: Provider
|
|
@@ -441,6 +442,8 @@ export type SignInWithOAuthCredentials = {
|
|
|
441
442
|
queryParams?: { [key: string]: string }
|
|
442
443
|
/** If set to true does not immediately redirect the current browser context to visit the OAuth authorization page for the provider. */
|
|
443
444
|
skipBrowserRedirect?: boolean
|
|
445
|
+
/** If set to 'pkce' PKCE flow. Defaults to the 'implicit' flow otherwise */
|
|
446
|
+
flowType?: OAuthFlowType
|
|
444
447
|
}
|
|
445
448
|
}
|
|
446
449
|
|
package/src/lib/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '2.
|
|
2
|
+
export const version = '2.18.0'
|