I'm developing an Android app using Firebase Authentication (email/password) with Jetpack Compose and Kotlin. The app stores user data locally in DataStore and sets a loggedIn flag to true after successful login and email verification.
On cold start (after killing the app process), FirebaseAuth.getInstance().currentUser returns null, even though DataStore contains valid user data. This causes the app to incorrectly redirect to the onboarding screen instead of restoring the session.
Log:
2025-08-03 10:39:59.094 12114-12114 FirebearStorageCryptoHelper com.example.pawgress E Exception encountered during crypto setup: Keystore cannot load the key with ID: firebear_main_key_id_for_storage_crypto... 2025-08-03 10:39:59.094 12114-12114 FirebearStorageCryptoHelper com.example.pawgress E KeysetManager failed to initialize - unable to decrypt data
2025-08-03 10:39:59.095 12114-12114 PawgressApplication com.example.pawgress D Firebase Auth initialized, currentUser: null
2025-08-03 10:39:59.904 12114-12114 SplashScreen com.example.pawgress D Auth state changed: null Checking local session: userId=bU36t4SAe8fDqrpCxhMfNS2SlKm1, flag=true
2025-08-03 10:40:01.920 12114-12114 UserRepository com.example.pawgress D Has local user data: true
This seems related to Android Keystore failing to decrypt Firebase's authentication tokens, causing the session to be lost. The issue occurs consistently on my Redmi Note 13 running HyperOS 2.0.206.0 (Android 13).
What I've Tried
Updated Firebase SDK: Using com.google.firebase:firebase-auth:23.2.0 with firebase-bom:33.16.0 — issue persists.
AuthStateListener: Added listener, but it either doesn’t fire or returns null for 10–20 seconds:
firebaseAuth.addAuthStateListener { auth ->
Log.d("PawgressApplication", "Auth state changed: ${auth.currentUser}")
}
- Polling for currentUser: Tried polling .currentUser with delay, stays null:
while (firebaseUser == null && retries < maxRetries) {
firebaseUser = firebaseAuth.currentUser
delay(1000)
retries++
}
Cleared app data: Reset app via settings, logged in again — issue still happens on cold start.
Disabled HyperOS optimizations: Turned off system-level optimizations — no effect.
Verified email: Email verification works correctly (verified flag true in logs).
Checked DataStore: Local user info is accurate (userId, email, loggedIn == true).
Checked Google Play Services: Installed, up-to-date, available.
Searched for similar issues: Found threads mentioning Keystore issues on MIUI/HyperOS devices, but none offered a working fix.
Code Snippet (SplashScreen Logic)
var firebaseUser = firebaseAuth.currentUser
var retries = 0
val maxRetries = 10
val retryDelay = 2000L
Log.d("SplashScreen", "🔍 Initial Firebase user: ${firebaseUser?.uid}")
var authStateReceived = false
val authStateListener = FirebaseAuth.AuthStateListener { auth ->
firebaseUser = auth.currentUser
authStateReceived = true
Log.d("SplashScreen", "🔄 Auth state changed: ${firebaseUser?.uid}")
}
firebaseAuth.addAuthStateListener(authStateListener)
while (!authStateReceived && retries < maxRetries) {
Log.d("SplashScreen", "🔄 Waiting for auth state, retry $retries/$maxRetries")
delay(retryDelay)
retries++
}
firebaseAuth.removeAuthStateListener(authStateListener)
val safeUser = firebaseUser
if (safeUser != null) {
try {
safeUser.reload().await()
Log.d("SplashScreen", "✅ Firebase user reloaded: ${safeUser.uid}, verified: ${safeUser.isEmailVerified}")
} catch (e: Exception) {
Log.e("SplashScreen", "Error reloading Firebase user: ${e.message}")
}
}
val localSessionValid = userRepository.hasValidLocalSession()
val localUser = userRepository.getUser().first()
val isLoggedIn = safeUser != null &&
safeUser.isEmailVerified &&
localUser != null &&
safeUser.uid == localUser.id &&
localSessionValid
val hasLocalUser = userRepository.hasLocalUserData()
Log.d("SplashScreen", "📊 Final state - firebaseUser: ${safeUser?.uid}, isLoggedIn: $isLoggedIn, hasLocalUser: $hasLocalUser")
if (isLoggedIn && hasLocalUser) {
val surveyCompleted = userRepository.isSurveyCompleted().first()
val petNamed = userRepository.isPetNamedFlow().first()
Log.d("SplashScreen", "📋 Survey completed: $surveyCompleted, Pet named: $petNamed")
when {
!surveyCompleted -> onTimeout("survey/1")
!petNamed -> onTimeout("pet_naming")
else -> onTimeout("home")
}
} else {
Log.w("SplashScreen", "⚠️ Incomplete login - redirecting to onboarding")
onTimeout("onboarding")
}
}