@supabase/gotrue-js 2.40.0 → 2.41.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 +13 -0
- package/dist/main/GoTrueClient.d.ts.map +1 -1
- package/dist/main/GoTrueClient.js +229 -180
- package/dist/main/GoTrueClient.js.map +1 -1
- package/dist/main/lib/helpers.d.ts +23 -0
- package/dist/main/lib/helpers.d.ts.map +1 -1
- package/dist/main/lib/helpers.js +94 -1
- 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/GoTrueClient.d.ts +13 -0
- package/dist/module/GoTrueClient.d.ts.map +1 -1
- package/dist/module/GoTrueClient.js +230 -181
- package/dist/module/GoTrueClient.js.map +1 -1
- package/dist/module/lib/helpers.d.ts +23 -0
- package/dist/module/lib/helpers.d.ts.map +1 -1
- package/dist/module/lib/helpers.js +91 -0
- 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 +3 -3
- package/src/GoTrueClient.ts +280 -205
- package/src/lib/helpers.ts +111 -0
- package/src/lib/version.ts +1 -1
package/src/GoTrueClient.ts
CHANGED
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
generatePKCEVerifier,
|
|
30
30
|
generatePKCEChallenge,
|
|
31
31
|
supportsLocalStorage,
|
|
32
|
+
stackGuard,
|
|
33
|
+
isInStackGuard,
|
|
32
34
|
} from './lib/helpers'
|
|
33
35
|
import localStorageAdapter from './lib/local-storage'
|
|
34
36
|
import { polyfillGlobalThis } from './lib/polyfills'
|
|
@@ -279,8 +281,6 @@ export default class GoTrueClient {
|
|
|
279
281
|
redirectType
|
|
280
282
|
)
|
|
281
283
|
|
|
282
|
-
await this._saveSession(session)
|
|
283
|
-
|
|
284
284
|
setTimeout(async () => {
|
|
285
285
|
if (redirectType === 'recovery') {
|
|
286
286
|
await this._notifyAllSubscribers('PASSWORD_RECOVERY', session)
|
|
@@ -291,7 +291,6 @@ export default class GoTrueClient {
|
|
|
291
291
|
|
|
292
292
|
return { error: null }
|
|
293
293
|
}
|
|
294
|
-
|
|
295
294
|
// no login attempt via callback url try to recover session from storage
|
|
296
295
|
await this._recoverAndRefresh()
|
|
297
296
|
return { error: null }
|
|
@@ -699,18 +698,20 @@ export default class GoTrueClient {
|
|
|
699
698
|
*/
|
|
700
699
|
async reauthenticate(): Promise<AuthResponse> {
|
|
701
700
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
701
|
+
return await this._useSession(async (result) => {
|
|
702
|
+
const {
|
|
703
|
+
data: { session },
|
|
704
|
+
error: sessionError,
|
|
705
|
+
} = result
|
|
706
|
+
if (sessionError) throw sessionError
|
|
707
|
+
if (!session) throw new AuthSessionMissingError()
|
|
708
708
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
709
|
+
const { error } = await _request(this.fetch, 'GET', `${this.url}/reauthenticate`, {
|
|
710
|
+
headers: this.headers,
|
|
711
|
+
jwt: session.access_token,
|
|
712
|
+
})
|
|
713
|
+
return { data: { user: null, session: null }, error }
|
|
712
714
|
})
|
|
713
|
-
return { data: { user: null, session: null }, error }
|
|
714
715
|
} catch (error) {
|
|
715
716
|
if (isAuthError(error)) {
|
|
716
717
|
return { data: { user: null, session: null }, error }
|
|
@@ -768,7 +769,55 @@ export default class GoTrueClient {
|
|
|
768
769
|
* Returns the session, refreshing it if necessary.
|
|
769
770
|
* 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.
|
|
770
771
|
*/
|
|
771
|
-
async getSession()
|
|
772
|
+
async getSession() {
|
|
773
|
+
return this._useSession(async (result) => {
|
|
774
|
+
return result
|
|
775
|
+
})
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Use instead of {@link #getSession} inside the library. It is
|
|
780
|
+
* semantically usually what you want, as getting a session involves some
|
|
781
|
+
* processing afterwards that requires only one client operating on the
|
|
782
|
+
* session at once across multiple tabs or processes.
|
|
783
|
+
*/
|
|
784
|
+
private async _useSession<R>(
|
|
785
|
+
fn: (
|
|
786
|
+
result:
|
|
787
|
+
| {
|
|
788
|
+
data: {
|
|
789
|
+
session: Session
|
|
790
|
+
}
|
|
791
|
+
error: null
|
|
792
|
+
}
|
|
793
|
+
| {
|
|
794
|
+
data: {
|
|
795
|
+
session: null
|
|
796
|
+
}
|
|
797
|
+
error: AuthError
|
|
798
|
+
}
|
|
799
|
+
| {
|
|
800
|
+
data: {
|
|
801
|
+
session: null
|
|
802
|
+
}
|
|
803
|
+
error: null
|
|
804
|
+
}
|
|
805
|
+
) => Promise<R>
|
|
806
|
+
): Promise<R> {
|
|
807
|
+
return await stackGuard('_useSession', async () => {
|
|
808
|
+
// the use of __loadSession here is the only correct use of the function!
|
|
809
|
+
const result = await this.__loadSession()
|
|
810
|
+
|
|
811
|
+
return await fn(result)
|
|
812
|
+
})
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* NEVER USE DIRECTLY!
|
|
817
|
+
*
|
|
818
|
+
* Always use {@link #_useSession}.
|
|
819
|
+
*/
|
|
820
|
+
private async __loadSession(): Promise<
|
|
772
821
|
| {
|
|
773
822
|
data: {
|
|
774
823
|
session: Session
|
|
@@ -788,11 +837,15 @@ export default class GoTrueClient {
|
|
|
788
837
|
error: null
|
|
789
838
|
}
|
|
790
839
|
> {
|
|
840
|
+
if (this.logDebugMessages && !isInStackGuard('_useSession')) {
|
|
841
|
+
throw new Error('Please use #_useSession()')
|
|
842
|
+
}
|
|
843
|
+
|
|
791
844
|
// make sure we've read the session from the url if there is one
|
|
792
845
|
// save to just await, as long we make sure _initialize() never throws
|
|
793
846
|
await this.initializePromise
|
|
794
847
|
|
|
795
|
-
this._debug('#
|
|
848
|
+
this._debug('#__loadSession()', 'begin')
|
|
796
849
|
|
|
797
850
|
try {
|
|
798
851
|
let currentSession: Session | null = null
|
|
@@ -824,7 +877,7 @@ export default class GoTrueClient {
|
|
|
824
877
|
: false
|
|
825
878
|
|
|
826
879
|
this._debug(
|
|
827
|
-
'#
|
|
880
|
+
'#__loadSession()',
|
|
828
881
|
`session has${hasExpired ? '' : ' not'} expired`,
|
|
829
882
|
'expires_at',
|
|
830
883
|
currentSession.expires_at
|
|
@@ -841,7 +894,7 @@ export default class GoTrueClient {
|
|
|
841
894
|
|
|
842
895
|
return { data: { session }, error: null }
|
|
843
896
|
} finally {
|
|
844
|
-
this._debug('#
|
|
897
|
+
this._debug('#__loadSession()', 'end')
|
|
845
898
|
}
|
|
846
899
|
}
|
|
847
900
|
|
|
@@ -851,20 +904,22 @@ export default class GoTrueClient {
|
|
|
851
904
|
*/
|
|
852
905
|
async getUser(jwt?: string): Promise<UserResponse> {
|
|
853
906
|
try {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
907
|
+
return await this._useSession(async (result) => {
|
|
908
|
+
if (!jwt) {
|
|
909
|
+
const { data, error } = result
|
|
910
|
+
if (error) {
|
|
911
|
+
throw error
|
|
912
|
+
}
|
|
859
913
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
914
|
+
// Default to Authorization header if there is no existing session
|
|
915
|
+
jwt = data.session?.access_token ?? undefined
|
|
916
|
+
}
|
|
863
917
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
918
|
+
return await _request(this.fetch, 'GET', `${this.url}/user`, {
|
|
919
|
+
headers: this.headers,
|
|
920
|
+
jwt: jwt,
|
|
921
|
+
xform: _userResponse,
|
|
922
|
+
})
|
|
868
923
|
})
|
|
869
924
|
} catch (error) {
|
|
870
925
|
if (isAuthError(error)) {
|
|
@@ -885,27 +940,29 @@ export default class GoTrueClient {
|
|
|
885
940
|
} = {}
|
|
886
941
|
): Promise<UserResponse> {
|
|
887
942
|
try {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
943
|
+
return await this._useSession(async (result) => {
|
|
944
|
+
const { data: sessionData, error: sessionError } = result
|
|
945
|
+
if (sessionError) {
|
|
946
|
+
throw sessionError
|
|
947
|
+
}
|
|
948
|
+
if (!sessionData.session) {
|
|
949
|
+
throw new AuthSessionMissingError()
|
|
950
|
+
}
|
|
951
|
+
const session: Session = sessionData.session
|
|
952
|
+
const { data, error: userError } = await _request(this.fetch, 'PUT', `${this.url}/user`, {
|
|
953
|
+
headers: this.headers,
|
|
954
|
+
redirectTo: options?.emailRedirectTo,
|
|
955
|
+
body: attributes,
|
|
956
|
+
jwt: session.access_token,
|
|
957
|
+
xform: _userResponse,
|
|
958
|
+
})
|
|
959
|
+
if (userError) throw userError
|
|
960
|
+
session.user = data.user as User
|
|
961
|
+
await this._saveSession(session)
|
|
962
|
+
await this._notifyAllSubscribers('USER_UPDATED', session)
|
|
907
963
|
|
|
908
|
-
|
|
964
|
+
return { data: { user: session.user }, error: null }
|
|
965
|
+
})
|
|
909
966
|
} catch (error) {
|
|
910
967
|
if (isAuthError(error)) {
|
|
911
968
|
return { data: { user: null }, error }
|
|
@@ -997,29 +1054,31 @@ export default class GoTrueClient {
|
|
|
997
1054
|
*/
|
|
998
1055
|
async refreshSession(currentSession?: { refresh_token: string }): Promise<AuthResponse> {
|
|
999
1056
|
try {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1057
|
+
return await this._useSession(async (result) => {
|
|
1058
|
+
if (!currentSession) {
|
|
1059
|
+
const { data, error } = result
|
|
1060
|
+
if (error) {
|
|
1061
|
+
throw error
|
|
1062
|
+
}
|
|
1005
1063
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1064
|
+
currentSession = data.session ?? undefined
|
|
1065
|
+
}
|
|
1008
1066
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1067
|
+
if (!currentSession?.refresh_token) {
|
|
1068
|
+
throw new AuthSessionMissingError()
|
|
1069
|
+
}
|
|
1012
1070
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1071
|
+
const { session, error } = await this._callRefreshToken(currentSession.refresh_token)
|
|
1072
|
+
if (error) {
|
|
1073
|
+
return { data: { user: null, session: null }, error: error }
|
|
1074
|
+
}
|
|
1017
1075
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1076
|
+
if (!session) {
|
|
1077
|
+
return { data: { user: null, session: null }, error: null }
|
|
1078
|
+
}
|
|
1021
1079
|
|
|
1022
|
-
|
|
1080
|
+
return { data: { user: session.user, session }, error: null }
|
|
1081
|
+
})
|
|
1023
1082
|
} catch (error) {
|
|
1024
1083
|
if (isAuthError(error)) {
|
|
1025
1084
|
return { data: { user: null, session: null }, error }
|
|
@@ -1142,27 +1201,29 @@ export default class GoTrueClient {
|
|
|
1142
1201
|
* If using others scope, no `SIGNED_OUT` event is fired!
|
|
1143
1202
|
*/
|
|
1144
1203
|
async signOut({ scope }: SignOut = { scope: 'global' }): Promise<{ error: AuthError | null }> {
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1204
|
+
return await this._useSession(async (result) => {
|
|
1205
|
+
const { data, error: sessionError } = result
|
|
1206
|
+
if (sessionError) {
|
|
1207
|
+
return { error: sessionError }
|
|
1208
|
+
}
|
|
1209
|
+
const accessToken = data.session?.access_token
|
|
1210
|
+
if (accessToken) {
|
|
1211
|
+
const { error } = await this.admin.signOut(accessToken, scope)
|
|
1212
|
+
if (error) {
|
|
1213
|
+
// ignore 404s since user might not exist anymore
|
|
1214
|
+
// ignore 401s since an invalid or expired JWT should sign out the current session
|
|
1215
|
+
if (!(isAuthApiError(error) && (error.status === 404 || error.status === 401))) {
|
|
1216
|
+
return { error }
|
|
1217
|
+
}
|
|
1157
1218
|
}
|
|
1158
1219
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1220
|
+
if (scope !== 'others') {
|
|
1221
|
+
await this._removeSession()
|
|
1222
|
+
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`)
|
|
1223
|
+
await this._notifyAllSubscribers('SIGNED_OUT', null)
|
|
1224
|
+
}
|
|
1225
|
+
return { error: null }
|
|
1226
|
+
})
|
|
1166
1227
|
}
|
|
1167
1228
|
|
|
1168
1229
|
/**
|
|
@@ -1195,20 +1256,22 @@ export default class GoTrueClient {
|
|
|
1195
1256
|
}
|
|
1196
1257
|
|
|
1197
1258
|
private async _emitInitialSession(id: string): Promise<void> {
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1259
|
+
return await this._useSession(async (result) => {
|
|
1260
|
+
try {
|
|
1261
|
+
const {
|
|
1262
|
+
data: { session },
|
|
1263
|
+
error,
|
|
1264
|
+
} = result
|
|
1265
|
+
if (error) throw error
|
|
1204
1266
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1267
|
+
await this.stateChangeEmitters.get(id)?.callback('INITIAL_SESSION', session)
|
|
1268
|
+
this._debug('INITIAL_SESSION', 'callback id', id, 'session', session)
|
|
1269
|
+
} catch (err) {
|
|
1270
|
+
await this.stateChangeEmitters.get(id)?.callback('INITIAL_SESSION', null)
|
|
1271
|
+
this._debug('INITIAL_SESSION', 'callback id', id, 'error', err)
|
|
1272
|
+
console.error(err)
|
|
1273
|
+
}
|
|
1274
|
+
})
|
|
1212
1275
|
}
|
|
1213
1276
|
|
|
1214
1277
|
/**
|
|
@@ -1634,28 +1697,30 @@ export default class GoTrueClient {
|
|
|
1634
1697
|
const now = Date.now()
|
|
1635
1698
|
|
|
1636
1699
|
try {
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1700
|
+
return await this._useSession(async (result) => {
|
|
1701
|
+
const {
|
|
1702
|
+
data: { session },
|
|
1703
|
+
} = result
|
|
1704
|
+
|
|
1705
|
+
if (!session || !session.refresh_token || !session.expires_at) {
|
|
1706
|
+
this._debug('#_autoRefreshTokenTick()', 'no session')
|
|
1707
|
+
return
|
|
1708
|
+
}
|
|
1645
1709
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1710
|
+
// session will expire in this many ticks (or has already expired if <= 0)
|
|
1711
|
+
const expiresInTicks = Math.floor(
|
|
1712
|
+
(session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION
|
|
1713
|
+
)
|
|
1650
1714
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1715
|
+
this._debug(
|
|
1716
|
+
'#_autoRefreshTokenTick()',
|
|
1717
|
+
`access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`
|
|
1718
|
+
)
|
|
1655
1719
|
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1720
|
+
if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {
|
|
1721
|
+
await this._callRefreshToken(session.refresh_token)
|
|
1722
|
+
}
|
|
1723
|
+
})
|
|
1659
1724
|
} catch (e: any) {
|
|
1660
1725
|
console.error('Auto refresh tick failed with error. This is likely a transient error.', e)
|
|
1661
1726
|
}
|
|
@@ -1777,14 +1842,16 @@ export default class GoTrueClient {
|
|
|
1777
1842
|
|
|
1778
1843
|
private async _unenroll(params: MFAUnenrollParams): Promise<AuthMFAUnenrollResponse> {
|
|
1779
1844
|
try {
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1845
|
+
return await this._useSession(async (result) => {
|
|
1846
|
+
const { data: sessionData, error: sessionError } = result
|
|
1847
|
+
if (sessionError) {
|
|
1848
|
+
return { data: null, error: sessionError }
|
|
1849
|
+
}
|
|
1784
1850
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1851
|
+
return await _request(this.fetch, 'DELETE', `${this.url}/factors/${params.factorId}`, {
|
|
1852
|
+
headers: this.headers,
|
|
1853
|
+
jwt: sessionData?.session?.access_token,
|
|
1854
|
+
})
|
|
1788
1855
|
})
|
|
1789
1856
|
} catch (error) {
|
|
1790
1857
|
if (isAuthError(error)) {
|
|
@@ -1799,30 +1866,32 @@ export default class GoTrueClient {
|
|
|
1799
1866
|
*/
|
|
1800
1867
|
private async _enroll(params: MFAEnrollParams): Promise<AuthMFAEnrollResponse> {
|
|
1801
1868
|
try {
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1869
|
+
return await this._useSession(async (result) => {
|
|
1870
|
+
const { data: sessionData, error: sessionError } = result
|
|
1871
|
+
if (sessionError) {
|
|
1872
|
+
return { data: null, error: sessionError }
|
|
1873
|
+
}
|
|
1806
1874
|
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1875
|
+
const { data, error } = await _request(this.fetch, 'POST', `${this.url}/factors`, {
|
|
1876
|
+
body: {
|
|
1877
|
+
friendly_name: params.friendlyName,
|
|
1878
|
+
factor_type: params.factorType,
|
|
1879
|
+
issuer: params.issuer,
|
|
1880
|
+
},
|
|
1881
|
+
headers: this.headers,
|
|
1882
|
+
jwt: sessionData?.session?.access_token,
|
|
1883
|
+
})
|
|
1816
1884
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1885
|
+
if (error) {
|
|
1886
|
+
return { data: null, error }
|
|
1887
|
+
}
|
|
1820
1888
|
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1889
|
+
if (data?.totp?.qr_code) {
|
|
1890
|
+
data.totp.qr_code = `data:image/svg+xml;utf-8,${data.totp.qr_code}`
|
|
1891
|
+
}
|
|
1824
1892
|
|
|
1825
|
-
|
|
1893
|
+
return { data, error: null }
|
|
1894
|
+
})
|
|
1826
1895
|
} catch (error) {
|
|
1827
1896
|
if (isAuthError(error)) {
|
|
1828
1897
|
return { data: null, error }
|
|
@@ -1836,32 +1905,34 @@ export default class GoTrueClient {
|
|
|
1836
1905
|
*/
|
|
1837
1906
|
private async _verify(params: MFAVerifyParams): Promise<AuthMFAVerifyResponse> {
|
|
1838
1907
|
try {
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1908
|
+
return await this._useSession(async (result) => {
|
|
1909
|
+
const { data: sessionData, error: sessionError } = result
|
|
1910
|
+
if (sessionError) {
|
|
1911
|
+
return { data: null, error: sessionError }
|
|
1912
|
+
}
|
|
1843
1913
|
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1914
|
+
const { data, error } = await _request(
|
|
1915
|
+
this.fetch,
|
|
1916
|
+
'POST',
|
|
1917
|
+
`${this.url}/factors/${params.factorId}/verify`,
|
|
1918
|
+
{
|
|
1919
|
+
body: { code: params.code, challenge_id: params.challengeId },
|
|
1920
|
+
headers: this.headers,
|
|
1921
|
+
jwt: sessionData?.session?.access_token,
|
|
1922
|
+
}
|
|
1923
|
+
)
|
|
1924
|
+
if (error) {
|
|
1925
|
+
return { data: null, error }
|
|
1852
1926
|
}
|
|
1853
|
-
)
|
|
1854
|
-
if (error) {
|
|
1855
|
-
return { data: null, error }
|
|
1856
|
-
}
|
|
1857
1927
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1928
|
+
await this._saveSession({
|
|
1929
|
+
expires_at: Math.round(Date.now() / 1000) + data.expires_in,
|
|
1930
|
+
...data,
|
|
1931
|
+
})
|
|
1932
|
+
await this._notifyAllSubscribers('MFA_CHALLENGE_VERIFIED', data)
|
|
1863
1933
|
|
|
1864
|
-
|
|
1934
|
+
return { data, error }
|
|
1935
|
+
})
|
|
1865
1936
|
} catch (error) {
|
|
1866
1937
|
if (isAuthError(error)) {
|
|
1867
1938
|
return { data: null, error }
|
|
@@ -1875,20 +1946,22 @@ export default class GoTrueClient {
|
|
|
1875
1946
|
*/
|
|
1876
1947
|
private async _challenge(params: MFAChallengeParams): Promise<AuthMFAChallengeResponse> {
|
|
1877
1948
|
try {
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
return await _request(
|
|
1884
|
-
this.fetch,
|
|
1885
|
-
'POST',
|
|
1886
|
-
`${this.url}/factors/${params.factorId}/challenge`,
|
|
1887
|
-
{
|
|
1888
|
-
headers: this.headers,
|
|
1889
|
-
jwt: sessionData?.session?.access_token,
|
|
1949
|
+
return await this._useSession(async (result) => {
|
|
1950
|
+
const { data: sessionData, error: sessionError } = result
|
|
1951
|
+
if (sessionError) {
|
|
1952
|
+
return { data: null, error: sessionError }
|
|
1890
1953
|
}
|
|
1891
|
-
|
|
1954
|
+
|
|
1955
|
+
return await _request(
|
|
1956
|
+
this.fetch,
|
|
1957
|
+
'POST',
|
|
1958
|
+
`${this.url}/factors/${params.factorId}/challenge`,
|
|
1959
|
+
{
|
|
1960
|
+
headers: this.headers,
|
|
1961
|
+
jwt: sessionData?.session?.access_token,
|
|
1962
|
+
}
|
|
1963
|
+
)
|
|
1964
|
+
})
|
|
1892
1965
|
} catch (error) {
|
|
1893
1966
|
if (isAuthError(error)) {
|
|
1894
1967
|
return { data: null, error }
|
|
@@ -1946,39 +2019,41 @@ export default class GoTrueClient {
|
|
|
1946
2019
|
* {@see GoTrueMFAApi#getAuthenticatorAssuranceLevel}
|
|
1947
2020
|
*/
|
|
1948
2021
|
private async _getAuthenticatorAssuranceLevel(): Promise<AuthMFAGetAuthenticatorAssuranceLevelResponse> {
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2022
|
+
return await this._useSession(async (result) => {
|
|
2023
|
+
const {
|
|
2024
|
+
data: { session },
|
|
2025
|
+
error: sessionError,
|
|
2026
|
+
} = result
|
|
2027
|
+
if (sessionError) {
|
|
2028
|
+
return { data: null, error: sessionError }
|
|
2029
|
+
}
|
|
2030
|
+
if (!session) {
|
|
2031
|
+
return {
|
|
2032
|
+
data: { currentLevel: null, nextLevel: null, currentAuthenticationMethods: [] },
|
|
2033
|
+
error: null,
|
|
2034
|
+
}
|
|
1960
2035
|
}
|
|
1961
|
-
}
|
|
1962
2036
|
|
|
1963
|
-
|
|
2037
|
+
const payload = this._decodeJWT(session.access_token)
|
|
1964
2038
|
|
|
1965
|
-
|
|
2039
|
+
let currentLevel: AuthenticatorAssuranceLevels | null = null
|
|
1966
2040
|
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2041
|
+
if (payload.aal) {
|
|
2042
|
+
currentLevel = payload.aal
|
|
2043
|
+
}
|
|
1970
2044
|
|
|
1971
|
-
|
|
2045
|
+
let nextLevel: AuthenticatorAssuranceLevels | null = currentLevel
|
|
1972
2046
|
|
|
1973
|
-
|
|
1974
|
-
|
|
2047
|
+
const verifiedFactors =
|
|
2048
|
+
session.user.factors?.filter((factor: Factor) => factor.status === 'verified') ?? []
|
|
1975
2049
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2050
|
+
if (verifiedFactors.length > 0) {
|
|
2051
|
+
nextLevel = 'aal2'
|
|
2052
|
+
}
|
|
1979
2053
|
|
|
1980
|
-
|
|
2054
|
+
const currentAuthenticationMethods = payload.amr || []
|
|
1981
2055
|
|
|
1982
|
-
|
|
2056
|
+
return { data: { currentLevel, nextLevel, currentAuthenticationMethods }, error: null }
|
|
2057
|
+
})
|
|
1983
2058
|
}
|
|
1984
2059
|
}
|