@supabase/gotrue-js 2.15.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/GoTrueClient.d.ts +6 -0
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +82 -24
- 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 +4 -1
- 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 +6 -0
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +83 -25
- 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 +4 -1
- 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 +72 -5
- package/src/lib/helpers.ts +42 -1
- package/src/lib/types.ts +4 -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
|
|
@@ -378,14 +382,43 @@ export default class GoTrueClient {
|
|
|
378
382
|
*/
|
|
379
383
|
async signInWithOAuth(credentials: SignInWithOAuthCredentials): Promise<OAuthResponse> {
|
|
380
384
|
await this._removeSession()
|
|
381
|
-
|
|
385
|
+
|
|
386
|
+
return await this._handleProviderSignIn(credentials.provider, {
|
|
382
387
|
redirectTo: credentials.options?.redirectTo,
|
|
383
388
|
scopes: credentials.options?.scopes,
|
|
384
389
|
queryParams: credentials.options?.queryParams,
|
|
385
390
|
skipBrowserRedirect: credentials.options?.skipBrowserRedirect,
|
|
391
|
+
flowType: credentials.options?.flowType ?? 'implicit',
|
|
386
392
|
})
|
|
387
393
|
}
|
|
388
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Log in an existing user via a third-party provider.
|
|
397
|
+
*/
|
|
398
|
+
async exchangeCodeForSession(authCode: string): Promise<AuthResponse> {
|
|
399
|
+
const codeVerifier = await getItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`)
|
|
400
|
+
const { data, error } = await _request(
|
|
401
|
+
this.fetch,
|
|
402
|
+
'POST',
|
|
403
|
+
`${this.url}/token?grant_type=oauth_pkce`,
|
|
404
|
+
{
|
|
405
|
+
headers: this.headers,
|
|
406
|
+
body: {
|
|
407
|
+
auth_code: authCode,
|
|
408
|
+
code_verifier: codeVerifier,
|
|
409
|
+
},
|
|
410
|
+
xform: _sessionResponse,
|
|
411
|
+
}
|
|
412
|
+
)
|
|
413
|
+
await removeItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`)
|
|
414
|
+
if (error || !data) return { data: { user: null, session: null }, error }
|
|
415
|
+
if (data.session) {
|
|
416
|
+
await this._saveSession(data.session)
|
|
417
|
+
this._notifyAllSubscribers('SIGNED_IN', data.session)
|
|
418
|
+
}
|
|
419
|
+
return { data, error }
|
|
420
|
+
}
|
|
421
|
+
|
|
389
422
|
/**
|
|
390
423
|
* Allows signing in with an ID token issued by certain supported providers.
|
|
391
424
|
* The ID token is verified for validity and a new session is established.
|
|
@@ -941,9 +974,26 @@ export default class GoTrueClient {
|
|
|
941
974
|
|
|
942
975
|
this.stateChangeEmitters.set(id, subscription)
|
|
943
976
|
|
|
977
|
+
this.emitInitialSession(id)
|
|
978
|
+
|
|
944
979
|
return { data: { subscription } }
|
|
945
980
|
}
|
|
946
981
|
|
|
982
|
+
private async emitInitialSession(id: string): Promise<void> {
|
|
983
|
+
try {
|
|
984
|
+
const {
|
|
985
|
+
data: { session },
|
|
986
|
+
error,
|
|
987
|
+
} = await this.getSession()
|
|
988
|
+
if (error) throw error
|
|
989
|
+
|
|
990
|
+
this.stateChangeEmitters.get(id)?.callback('INITIAL_SESSION', session)
|
|
991
|
+
} catch (err) {
|
|
992
|
+
this.stateChangeEmitters.get(id)?.callback('INITIAL_SESSION', null)
|
|
993
|
+
console.error(err)
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
947
997
|
/**
|
|
948
998
|
* Sends a password reset request to an email address.
|
|
949
999
|
* @param email The email address of the user.
|
|
@@ -1023,24 +1073,27 @@ export default class GoTrueClient {
|
|
|
1023
1073
|
return isValidSession
|
|
1024
1074
|
}
|
|
1025
1075
|
|
|
1026
|
-
private _handleProviderSignIn(
|
|
1076
|
+
private async _handleProviderSignIn(
|
|
1027
1077
|
provider: Provider,
|
|
1028
1078
|
options: {
|
|
1029
1079
|
redirectTo?: string
|
|
1030
1080
|
scopes?: string
|
|
1031
1081
|
queryParams?: { [key: string]: string }
|
|
1032
1082
|
skipBrowserRedirect?: boolean
|
|
1033
|
-
|
|
1083
|
+
flowType: OAuthFlowType
|
|
1084
|
+
}
|
|
1034
1085
|
) {
|
|
1035
|
-
const url: string = this._getUrlForProvider(provider, {
|
|
1086
|
+
const url: string = await this._getUrlForProvider(provider, {
|
|
1036
1087
|
redirectTo: options.redirectTo,
|
|
1037
1088
|
scopes: options.scopes,
|
|
1038
1089
|
queryParams: options.queryParams,
|
|
1090
|
+
flowType: options.flowType,
|
|
1039
1091
|
})
|
|
1040
1092
|
// try to open on the browser
|
|
1041
1093
|
if (isBrowser() && !options.skipBrowserRedirect) {
|
|
1042
1094
|
window.location.assign(url)
|
|
1043
1095
|
}
|
|
1096
|
+
|
|
1044
1097
|
return { data: { provider, url }, error: null }
|
|
1045
1098
|
}
|
|
1046
1099
|
|
|
@@ -1338,13 +1391,15 @@ export default class GoTrueClient {
|
|
|
1338
1391
|
* @param options.redirectTo A URL or mobile address to send the user to after they are confirmed.
|
|
1339
1392
|
* @param options.scopes A space-separated list of scopes granted to the OAuth application.
|
|
1340
1393
|
* @param options.queryParams An object of key-value pairs containing query parameters granted to the OAuth application.
|
|
1394
|
+
* @param options.flowType OAuth flow to use - defaults to implicit flow. PKCE is recommended for mobile and server-side applications.
|
|
1341
1395
|
*/
|
|
1342
|
-
private _getUrlForProvider(
|
|
1396
|
+
private async _getUrlForProvider(
|
|
1343
1397
|
provider: Provider,
|
|
1344
1398
|
options: {
|
|
1345
1399
|
redirectTo?: string
|
|
1346
1400
|
scopes?: string
|
|
1347
1401
|
queryParams?: { [key: string]: string }
|
|
1402
|
+
flowType: OAuthFlowType
|
|
1348
1403
|
}
|
|
1349
1404
|
) {
|
|
1350
1405
|
const urlParams: string[] = [`provider=${encodeURIComponent(provider)}`]
|
|
@@ -1354,10 +1409,22 @@ export default class GoTrueClient {
|
|
|
1354
1409
|
if (options?.scopes) {
|
|
1355
1410
|
urlParams.push(`scopes=${encodeURIComponent(options.scopes)}`)
|
|
1356
1411
|
}
|
|
1412
|
+
if (options?.flowType === 'pkce') {
|
|
1413
|
+
const codeVerifier = generatePKCEVerifier()
|
|
1414
|
+
await setItemAsync(this.storage, `${this.storageKey}-oauth-code-verifier`, codeVerifier)
|
|
1415
|
+
const codeChallenge = await generatePKCEChallenge(codeVerifier)
|
|
1416
|
+
const flowParams = new URLSearchParams({
|
|
1417
|
+
flow_type: `${encodeURIComponent(options.flowType)}`,
|
|
1418
|
+
code_challenge: `${encodeURIComponent(codeChallenge)}`,
|
|
1419
|
+
code_challenge_method: `${encodeURIComponent('s256')}`,
|
|
1420
|
+
})
|
|
1421
|
+
urlParams.push(flowParams.toString())
|
|
1422
|
+
}
|
|
1357
1423
|
if (options?.queryParams) {
|
|
1358
1424
|
const query = new URLSearchParams(options.queryParams)
|
|
1359
1425
|
urlParams.push(query.toString())
|
|
1360
1426
|
}
|
|
1427
|
+
|
|
1361
1428
|
return `${this.url}/authorize?${urlParams.join('&')}`
|
|
1362
1429
|
}
|
|
1363
1430
|
|
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
|
@@ -23,6 +23,7 @@ export type Provider =
|
|
|
23
23
|
export type AuthChangeEventMFA = 'MFA_CHALLENGE_VERIFIED'
|
|
24
24
|
|
|
25
25
|
export type AuthChangeEvent =
|
|
26
|
+
| 'INITIAL_SESSION'
|
|
26
27
|
| 'PASSWORD_RECOVERY'
|
|
27
28
|
| 'SIGNED_IN'
|
|
28
29
|
| 'SIGNED_OUT'
|
|
@@ -428,6 +429,7 @@ export type SignInWithPasswordlessCredentials =
|
|
|
428
429
|
}
|
|
429
430
|
}
|
|
430
431
|
|
|
432
|
+
export type OAuthFlowType = 'implicit' | 'pkce'
|
|
431
433
|
export type SignInWithOAuthCredentials = {
|
|
432
434
|
/** One of the providers supported by GoTrue. */
|
|
433
435
|
provider: Provider
|
|
@@ -440,6 +442,8 @@ export type SignInWithOAuthCredentials = {
|
|
|
440
442
|
queryParams?: { [key: string]: string }
|
|
441
443
|
/** If set to true does not immediately redirect the current browser context to visit the OAuth authorization page for the provider. */
|
|
442
444
|
skipBrowserRedirect?: boolean
|
|
445
|
+
/** If set to 'pkce' PKCE flow. Defaults to the 'implicit' flow otherwise */
|
|
446
|
+
flowType?: OAuthFlowType
|
|
443
447
|
}
|
|
444
448
|
}
|
|
445
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.17.0'
|