Fixing Auth Flicker: Login Briefly Shows Before Home

by Editorial Team 53 views
Iklan Headers

Hey guys, have you ever experienced a brief flash of the login screen before landing on the home screen when you resume an app or wake up your device? It's a common issue, and it can be super confusing. This article dives into the root cause of this annoying "auth flicker" in the Shokken app, specifically the Auth flicker on resume: Login briefly shows before Home issue, explaining why it happens and how we can fix it. I'll break down the code-level details, the best practices, and the proposed solutions, making sure everyone can understand what's happening and how to solve it. Let's get started!

The Problem: Auth Bounce and User Confusion

When the app restarts or is resumed, especially after being in the background or killed, the user interface (UI) briefly shows the Login screen before instantly switching to Home. This creates an auth “bounce”, where the app seems to transition from an unauthenticated state to an authenticated state very quickly. This can lead to a less-than-ideal user experience, making users question if they are truly logged in or if there is something wrong with the app. It's confusing and can make the app feel clunky and unprofessional. We're here to fix it, so let's get into the technical nitty-gritty and see how it works!

Code-Level Confirmation: Tracing the Route

The root of this problem lies in how the app handles authentication and routing. The auth routing is driven by AuthenticationRepository.observeAuthState(). The observeAuthState() then determines which screen to show based on the AuthState. In App.kt, the destination is mapped as follows:

  • AuthState.NotAuthenticated is mapped to AuthDestination.Login.
  • AuthState.Authenticated is mapped to AuthDestination.Home.

The AuthenticationRepositoryImpl.kt then maps Supabase SessionStatus to AuthState. This is where the magic happens and where the problem arises. Specifically, SessionStatus.RefreshFailure is currently mapped to AuthState.NotAuthenticated. This means that when the session refresh fails, the app is wrongly considered as unauthenticated, which triggers the Login screen.

Now, here is the critical detail: SessionStatus.RefreshFailure is not equivalent to a user logging out. It means that the session has expired, and the authentication system is trying to refresh it. In other words, it is a transient state of attempting to refresh the session.

So, if the session tries to refresh and fails, the app briefly routes to Login and then back to Home, causing the login flash. The RefreshFailure triggers a routing to the Login page, and then, if the refresh succeeds, the app redirects back to Home, which causes the annoying Login → Home flash that we are discussing.

Why Does This Happen on Wake/Resume?

The issue primarily arises when the access token expires while the app is suspended or asleep. Supabase automatically attempts to refresh the token on resume using loadFromStorage(autoRefresh = true) and the internal refresh logic. During this process, the sessionStatus might emit RefreshFailure (due to network hiccups, server errors, or retries), and then later emit Authenticated once the refresh is successful.

Because RefreshFailure is treated as NotAuthenticated, the UI temporarily shows the Login screen. This is a crucial point: it’s not that the user has actually logged out, but the system is momentarily in a state where it's trying to refresh the user's session. It's a temporary hiccup, but because of the way the app handles this, it causes this annoying flicker.

Best Practices and References

To better understand how to solve this, let's look at some best practices and references. The first is Context7 (supabase-kt). The session persistence and initialization pattern is as follows:

  1. supabase.auth.loadFromStorage(autoRefresh = true)
  2. supabase.auth.awaitInitialization()
  3. Observe supabase.auth.sessionStatus

Upstream source docs (supabase-kt) also provide important information, such as the meaning of SessionStatus.RefreshFailure: "expired and trying to refresh it".

Proposed Fix: Correctly Handling Session Refresh

The primary fix, and the recommended one, is to treat SessionStatus.RefreshFailure as not a logout event.

There are two main options:

  1. Map RefreshFailure to AuthState.LoadingState or a new AuthState.Refreshing(...). This indicates that the app is in the process of refreshing the session and avoid sending the user to the Login page.
  2. Maintain the last stable auth destination. Once the user is on the Home page, don't redirect to Login unless a definitive NotAuthenticated signal is received (especially isSignOut = true) or the session is explicitly cleared.

Additional UI/UX Improvements

Besides the main fix, there are also a couple of UI/UX improvements to provide a better user experience:

  • Display a non-disruptive “Reconnecting…” or an offline banner, or an overlay, while the refresh is in progress instead of switching to the Login screen.
  • On Android, consider holding the splash screen until the initial auth state is resolved.

Conclusion: A Better User Experience

By implementing the proposed fix and considering the optional UI/UX improvements, the app will no longer briefly show the Login screen when the user resumes or restarts the app. The app will maintain a seamless transition, preserving the user’s logged-in state. This ensures that the user's experience is smooth and frustration-free. By treating RefreshFailure correctly, we can create a much better user experience.