@@ -26,6 +26,7 @@ import {
2626 getBrandingPreference ,
2727 GetBrandingPreferenceConfig ,
2828 BrandingPreference ,
29+ IdToken ,
2930} from '@asgardeo/browser' ;
3031import { FC , RefObject , PropsWithChildren , ReactElement , useEffect , useMemo , useRef , useState , useCallback } from 'react' ;
3132import AsgardeoContext from './AsgardeoContext' ;
@@ -88,6 +89,8 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
8889 ...rest ,
8990 } ) ;
9091
92+ const [ isUpdatingSession , setIsUpdatingSession ] = useState < boolean > ( false ) ;
93+
9194 // Branding state
9295 const [ brandingPreference , setBrandingPreference ] = useState < BrandingPreference | null > ( null ) ;
9396 const [ isBrandingLoading , setIsBrandingLoading ] = useState < boolean > ( false ) ;
@@ -129,27 +132,32 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
129132
130133 ( async ( ) : Promise < void > => {
131134 // User is already authenticated. Skip...
132- if ( await asgardeo . isSignedIn ( ) ) {
133- await updateSession ( ) ;
135+ const isAlreadySignedIn : boolean = await asgardeo . isSignedIn ( ) ;
134136
137+ if ( isAlreadySignedIn ) {
138+ await updateSession ( ) ;
135139 return ;
136140 }
137141
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 ) {
139146 try {
140147 await signIn (
141148 { callOnlyOnRedirect : true } ,
142149 // authParams?.authorizationCode,
143150 // authParams?.sessionState,
144151 // authParams?.state,
145152 ) ;
146-
147153 // setError(null);
148154 } catch ( error ) {
149155 if ( error && Object . prototype . hasOwnProperty . call ( error , 'code' ) ) {
150156 // setError(error);
151157 }
152158 }
159+ } else {
160+ // TODO: Add a debug log to indicate that the user is not signed in
153161 }
154162 } ) ( ) ;
155163 } , [ ] ) ;
@@ -177,6 +185,8 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
177185 clearInterval ( interval ) ;
178186 }
179187 } , 1000 ) ;
188+ } else {
189+ // TODO: Add a debug log to indicate that the user is already signed in.
180190 }
181191 } catch ( error ) {
182192 setIsSignedInSync ( false ) ;
@@ -207,8 +217,12 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
207217 */
208218 useEffect ( ( ) => {
209219 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 ( ) ) ;
212226 } ;
213227
214228 // Initial check
@@ -220,25 +234,44 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
220234 return ( ) : void => {
221235 clearInterval ( interval ) ;
222236 } ;
223- } , [ asgardeo ] ) ;
237+ } , [ asgardeo , isLoadingSync , isSignedInSync , isUpdatingSession ] ) ;
224238
225239 const updateSession = async ( ) : Promise < void > => {
226240 try {
241+ // Set flag to prevent loading state tracking from interfering
242+ setIsUpdatingSession ( true ) ;
227243 setIsLoadingSync ( true ) ;
228244 let _baseUrl : string = baseUrl ;
229245
246+ const decodedToken : IdToken = await asgardeo . getDecodedIdToken ( ) ;
247+
230248 // If there's a `user_org` claim in the ID token,
231249 // Treat this login as a organization login.
232- if ( ( await asgardeo . getDecodedIdToken ( ) ) ?. [ 'user_org' ] ) {
250+ if ( decodedToken ?. [ 'user_org' ] ) {
233251 _baseUrl = `${ ( await asgardeo . getConfiguration ( ) ) . baseUrl } /o` ;
234252 setBaseUrl ( _baseUrl ) ;
235253 }
236254
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.
241272 } finally {
273+ // Clear the flag and set final loading state
274+ setIsUpdatingSession ( false ) ;
242275 setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
243276 }
244277 } ;
@@ -302,6 +335,7 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
302335
303336 const signIn = async ( ...args : any ) : Promise < User > => {
304337 try {
338+ setIsUpdatingSession ( true ) ;
305339 setIsLoadingSync ( true ) ;
306340 const response : User = await asgardeo . signIn ( ...args ) ;
307341
@@ -313,12 +347,14 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
313347 } catch ( error ) {
314348 throw new Error ( `Error while signing in: ${ error } ` ) ;
315349 } finally {
350+ setIsUpdatingSession ( false ) ;
316351 setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
317352 }
318353 } ;
319354
320355 const signInSilently = async ( options ?: SignInOptions ) : Promise < User | boolean > => {
321356 try {
357+ setIsUpdatingSession ( true ) ;
322358 setIsLoadingSync ( true ) ;
323359 const response : User | boolean = await asgardeo . signInSilently ( options ) ;
324360
@@ -335,12 +371,14 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
335371 'An error occurred while trying to sign in silently.' ,
336372 ) ;
337373 } finally {
374+ setIsUpdatingSession ( false ) ;
338375 setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
339376 }
340377 } ;
341378
342379 const switchOrganization = async ( organization : Organization ) : Promise < void > => {
343380 try {
381+ setIsUpdatingSession ( true ) ;
344382 setIsLoadingSync ( true ) ;
345383 await asgardeo . switchOrganization ( organization ) ;
346384
@@ -355,6 +393,7 @@ const AsgardeoProvider: FC<PropsWithChildren<AsgardeoProviderProps>> = ({
355393 'An error occurred while switching to the specified organization.' ,
356394 ) ;
357395 } finally {
396+ setIsUpdatingSession ( false ) ;
358397 setIsLoadingSync ( asgardeo . isLoading ( ) ) ;
359398 }
360399 } ;
0 commit comments