@@ -26,6 +26,7 @@ import {
26
26
getBrandingPreference ,
27
27
GetBrandingPreferenceConfig ,
28
28
BrandingPreference ,
29
+ IdToken ,
29
30
} from '@asgardeo/browser' ;
30
31
import { FC , RefObject , PropsWithChildren , ReactElement , useEffect , useMemo , useRef , useState , useCallback } from 'react' ;
31
32
import AsgardeoContext from './AsgardeoContext' ;
@@ -88,6 +89,8 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
88
89
...rest ,
89
90
} ) ;
90
91
92
+ const [ isUpdatingSession , setIsUpdatingSession ] = useState < boolean > ( false ) ;
93
+
91
94
// Branding state
92
95
const [ brandingPreference , setBrandingPreference ] = useState < BrandingPreference | null > ( null ) ;
93
96
const [ isBrandingLoading , setIsBrandingLoading ] = useState < boolean > ( false ) ;
@@ -129,27 +132,32 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
129
132
130
133
( async ( ) : Promise < void > => {
131
134
// User is already authenticated. Skip...
132
- if ( await asgardeo . isSignedIn ( ) ) {
133
- await updateSession ( ) ;
135
+ const isAlreadySignedIn : boolean = await asgardeo . isSignedIn ( ) ;
134
136
137
+ if ( isAlreadySignedIn ) {
138
+ await updateSession ( ) ;
135
139
return ;
136
140
}
137
141
138
- if ( hasAuthParams ( new URL ( window . location . href ) , afterSignInUrl ) ) {
142
+ const currentUrl : URL = new URL ( window . location . href ) ;
143
+ const hasAuthParamsResult : boolean = hasAuthParams ( currentUrl , afterSignInUrl ) ;
144
+
145
+ if ( hasAuthParamsResult ) {
139
146
try {
140
147
await signIn (
141
148
{ callOnlyOnRedirect : true } ,
142
149
// authParams?.authorizationCode,
143
150
// authParams?.sessionState,
144
151
// authParams?.state,
145
152
) ;
146
-
147
153
// setError(null);
148
154
} catch ( error ) {
149
155
if ( error && Object . prototype . hasOwnProperty . call ( error , 'code' ) ) {
150
156
// setError(error);
151
157
}
152
158
}
159
+ } else {
160
+ // TODO: Add a debug log to indicate that the user is not signed in
153
161
}
154
162
} ) ( ) ;
155
163
} , [ ] ) ;
@@ -177,6 +185,8 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
177
185
clearInterval ( interval ) ;
178
186
}
179
187
} , 1000 ) ;
188
+ } else {
189
+ // TODO: Add a debug log to indicate that the user is already signed in.
180
190
}
181
191
} catch ( error ) {
182
192
setIsSignedInSync ( false ) ;
@@ -207,8 +217,12 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
207
217
*/
208
218
useEffect ( ( ) => {
209
219
const checkLoadingState = ( ) : void => {
210
- const loadingState = asgardeo . isLoading ( ) ;
211
- setIsLoadingSync ( loadingState ) ;
220
+ // Don't override loading state during critical session updates
221
+ if ( isUpdatingSession ) {
222
+ return ;
223
+ }
224
+
225
+ setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
212
226
} ;
213
227
214
228
// Initial check
@@ -220,25 +234,44 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
220
234
return ( ) : void => {
221
235
clearInterval ( interval ) ;
222
236
} ;
223
- } , [ asgardeo ] ) ;
237
+ } , [ asgardeo , isLoadingSync , isSignedInSync , isUpdatingSession ] ) ;
224
238
225
239
const updateSession = async ( ) : Promise < void > => {
226
240
try {
241
+ // Set flag to prevent loading state tracking from interfering
242
+ setIsUpdatingSession ( true ) ;
227
243
setIsLoadingSync ( true ) ;
228
244
let _baseUrl : string = baseUrl ;
229
245
246
+ const decodedToken : IdToken = await asgardeo . getDecodedIdToken ( ) ;
247
+
230
248
// If there's a `user_org` claim in the ID token,
231
249
// Treat this login as a organization login.
232
- if ( ( await asgardeo . getDecodedIdToken ( ) ) ?. [ 'user_org' ] ) {
250
+ if ( decodedToken ?. [ 'user_org' ] ) {
233
251
_baseUrl = `${ ( await asgardeo . getConfiguration ( ) ) . baseUrl } /o` ;
234
252
setBaseUrl ( _baseUrl ) ;
235
253
}
236
254
237
- setUser ( await asgardeo . getUser ( { baseUrl : _baseUrl } ) ) ;
238
- setUserProfile ( await asgardeo . getUserProfile ( { baseUrl : _baseUrl } ) ) ;
239
- setCurrentOrganization ( await asgardeo . getCurrentOrganization ( ) ) ;
240
- setMyOrganizations ( await asgardeo . getMyOrganizations ( ) ) ;
255
+ const user : User = await asgardeo . getUser ( { baseUrl : _baseUrl } ) ;
256
+ const userProfile : UserProfile = await asgardeo . getUserProfile ( { baseUrl : _baseUrl } ) ;
257
+ const currentOrganization : Organization = await asgardeo . getCurrentOrganization ( ) ;
258
+ const myOrganizations : Organization [ ] = await asgardeo . getMyOrganizations ( ) ;
259
+
260
+ // Update user data first
261
+ setUser ( user ) ;
262
+ setUserProfile ( userProfile ) ;
263
+ setCurrentOrganization ( currentOrganization ) ;
264
+ setMyOrganizations ( myOrganizations ) ;
265
+
266
+ // CRITICAL: Update sign-in status BEFORE setting loading to false
267
+ // This prevents the race condition where ProtectedRoute sees isLoading=false but isSignedIn=false
268
+ const currentSignInStatus = await asgardeo . isSignedIn ( ) ;
269
+ setIsSignedInSync ( await asgardeo . isSignedIn ( ) ) ;
270
+ } catch ( error ) {
271
+ // TODO: Add an error log.
241
272
} finally {
273
+ // Clear the flag and set final loading state
274
+ setIsUpdatingSession ( false ) ;
242
275
setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
243
276
}
244
277
} ;
@@ -302,6 +335,7 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
302
335
303
336
const signIn = async ( ...args : any ) : Promise < User > => {
304
337
try {
338
+ setIsUpdatingSession ( true ) ;
305
339
setIsLoadingSync ( true ) ;
306
340
const response : User = await asgardeo . signIn ( ...args ) ;
307
341
@@ -313,12 +347,14 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
313
347
} catch ( error ) {
314
348
throw new Error ( `Error while signing in: ${ error } ` ) ;
315
349
} finally {
350
+ setIsUpdatingSession ( false ) ;
316
351
setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
317
352
}
318
353
} ;
319
354
320
355
const signInSilently = async ( options ?: SignInOptions ) : Promise < User | boolean > => {
321
356
try {
357
+ setIsUpdatingSession ( true ) ;
322
358
setIsLoadingSync ( true ) ;
323
359
const response : User | boolean = await asgardeo . signInSilently ( options ) ;
324
360
@@ -335,12 +371,14 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
335
371
'An error occurred while trying to sign in silently.' ,
336
372
) ;
337
373
} finally {
374
+ setIsUpdatingSession ( false ) ;
338
375
setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
339
376
}
340
377
} ;
341
378
342
379
const switchOrganization = async ( organization : Organization ) : Promise < void > => {
343
380
try {
381
+ setIsUpdatingSession ( true ) ;
344
382
setIsLoadingSync ( true ) ;
345
383
await asgardeo . switchOrganization ( organization ) ;
346
384
@@ -355,6 +393,7 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
355
393
'An error occurred while switching to the specified organization.' ,
356
394
) ;
357
395
} finally {
396
+ setIsUpdatingSession ( false ) ;
358
397
setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
359
398
}
360
399
} ;
0 commit comments