Skip to content

Commit c85a6e8

Browse files
fix: concurrent credential storage errors by preventing unnecessary state updates (#1302)
1 parent fb31537 commit c85a6e8

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

src/core/utils/deepEqual.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export function deepEqual<T>(x: T, y: T): boolean {
2+
if (x === y) {
3+
return true;
4+
} else if (
5+
typeof x == 'object' &&
6+
x != null &&
7+
typeof y == 'object' &&
8+
y != null
9+
) {
10+
if (Object.keys(x).length != Object.keys(y).length) return false;
11+
12+
for (const prop in x) {
13+
if (Object.prototype.hasOwnProperty.call(y, prop)) {
14+
if (!deepEqual(x[prop], y[prop])) return false;
15+
} else return false;
16+
}
17+
return true;
18+
} else {
19+
return false;
20+
}
21+
}

src/hooks/Auth0Provider.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,21 +146,31 @@ export const Auth0Provider = ({
146146
);
147147

148148
const getCredentials = useCallback(
149-
(
149+
async (
150150
scope?: string,
151151
minTtl?: number,
152152
parameters?: Record<string, unknown>,
153153
forceRefresh?: boolean
154-
) =>
155-
loginFlow(
156-
client.credentialsManager.getCredentials(
154+
) => {
155+
try {
156+
const credentials = await client.credentialsManager.getCredentials(
157157
scope,
158158
minTtl,
159159
parameters,
160160
forceRefresh
161-
)
162-
),
163-
[client, loginFlow]
161+
);
162+
if (credentials.idToken) {
163+
const user = Auth0User.fromIdToken(credentials.idToken);
164+
dispatch({ type: 'SET_USER', user });
165+
}
166+
return credentials;
167+
} catch (e) {
168+
const error = e as AuthError;
169+
dispatch({ type: 'ERROR', error });
170+
throw error;
171+
}
172+
},
173+
[client]
164174
);
165175

166176
const hasValidCredentials = useCallback(

src/hooks/reducer.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { User } from '../types';
22
import type { AuthError } from '../core/models';
3+
import { deepEqual } from '../core/utils/deepEqual';
34

45
/**
56
* The shape of the authentication state managed by the Auth0Provider.
@@ -18,7 +19,8 @@ export type AuthAction =
1819
| { type: 'LOGIN_COMPLETE'; user: User }
1920
| { type: 'LOGOUT_COMPLETE' }
2021
| { type: 'ERROR'; error: AuthError }
21-
| { type: 'INITIALIZED'; user: User | null };
22+
| { type: 'INITIALIZED'; user: User | null }
23+
| { type: 'SET_USER'; user: User | null };
2224

2325
/**
2426
* A pure function that calculates the new state based on the previous state and a dispatched action.
@@ -34,5 +36,10 @@ export const reducer = (state: AuthState, action: AuthAction): AuthState => {
3436
return { ...state, isLoading: false, error: action.error };
3537
case 'INITIALIZED':
3638
return { ...state, isLoading: false, user: action.user };
39+
case 'SET_USER':
40+
if (deepEqual(state.user, action.user)) {
41+
return state;
42+
}
43+
return { ...state, user: action.user };
3744
}
3845
};

0 commit comments

Comments
 (0)