Skip to main content
deleted 394 characters in body
Source Link
Frank van Puffelen
  • 603.3k
  • 85
  • 895
  • 869

I'm 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.

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

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

*WhatWhat I've Tried*Tried

firebaseAuth.addAuthStateListener { auth ->  
    Log.d("PawgressApplication", "Auth state changed: ${auth.currentUser}")  
}
while (firebaseUser == null && retries < maxRetries) {  
    firebaseUser = firebaseAuth.currentUser  
    delay(1000)  
    retries++  
}
            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")
            }
        } 

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.

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

*What I've Tried*

firebaseAuth.addAuthStateListener { auth ->     Log.d("PawgressApplication", "Auth state changed: ${auth.currentUser}") }
while (firebaseUser == null && retries < maxRetries) {     firebaseUser = firebaseAuth.currentUser     delay(1000)     retries++ }
            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")
            }
        } 

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.

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

What I've Tried

firebaseAuth.addAuthStateListener { auth ->  
    Log.d("PawgressApplication", "Auth state changed: ${auth.currentUser}")  
}
while (firebaseUser == null && retries < maxRetries) { 
    firebaseUser = firebaseAuth.currentUser 
    delay(1000)  
    retries++  
}
    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")
    }
} 
Source Link

Firebase Auth currentUser null on cold start due to KeysetManager failed to initialize on Redmi Note 13 HyperOS

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")
            }
        } 
created from staging ground