diff --git a/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt b/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt index 6446b4c48..52298833d 100644 --- a/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt +++ b/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner import androidx.startup.Initializer import io.github.jan.supabase.annotations.SupabaseInternal -import io.github.jan.supabase.auth.status.SessionStatus import io.github.jan.supabase.logging.d import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -60,7 +59,7 @@ private fun addLifecycleCallbacks(auth: Auth) { auth.logger.d { "Cancelling auto refresh because app is switching to the background" } scope.launch { auth.stopAutoRefreshForCurrentSession() - auth.setSessionStatus(SessionStatus.Initializing) + auth.resetSessionStatusForBackground() } } } diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt index ec78ec500..0957db327 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt @@ -7,6 +7,7 @@ import io.github.jan.supabase.annotations.SupabaseExperimental import io.github.jan.supabase.annotations.SupabaseInternal import io.github.jan.supabase.auth.jwt.JwkCache import io.github.jan.supabase.auth.jwt.SharedJwkCache +import io.github.jan.supabase.auth.status.SessionStatus import io.github.jan.supabase.auth.user.UserSession import io.github.jan.supabase.plugins.CustomSerializationConfig import io.github.jan.supabase.plugins.MainConfig @@ -106,6 +107,19 @@ open class AuthConfigDefaults : MainConfig(), AuthDependentPluginConfig, CustomS */ var enableLifecycleCallbacks: Boolean = true + /** + * Whether to reset [Auth.sessionStatus] to [SessionStatus.Initializing] when the app moves to + * the background. + * + * When `true` (default), the status is reset on background and re-established on resume, which + * means consumers observe a transient [SessionStatus.Initializing] after every resume. When + * `false`, the last known status (e.g. [SessionStatus.Authenticated]) is kept while auto-refresh + * is paused, avoiding that transient state. + * + * Only has an effect when [enableLifecycleCallbacks] is `true`. Currently only supported on Android. + */ + var resetStatusOnBackground: Boolean = true + /** * The URL launcher used to open OAuth links in the system browser. */ diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/Utils.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/Utils.kt index 775d3bb24..5c654a2e9 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/Utils.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/Utils.kt @@ -23,6 +23,12 @@ internal fun Auth.initDone() { } } +internal fun Auth.resetSessionStatusForBackground() { + if(config.resetStatusOnBackground) { + setSessionStatus(SessionStatus.Initializing) + } +} + internal suspend fun Auth.tryToGetUser(accessToken: String) = try { retrieveUser(accessToken) } catch (e: Exception) { diff --git a/Auth/src/commonTest/kotlin/AuthTest.kt b/Auth/src/commonTest/kotlin/AuthTest.kt index 8cd98c8ee..0533b00a4 100644 --- a/Auth/src/commonTest/kotlin/AuthTest.kt +++ b/Auth/src/commonTest/kotlin/AuthTest.kt @@ -7,6 +7,7 @@ import io.github.jan.supabase.auth.auth import io.github.jan.supabase.auth.event.AuthEvent import io.github.jan.supabase.auth.minimalConfig import io.github.jan.supabase.auth.providers.Github +import io.github.jan.supabase.auth.resetSessionStatusForBackground import io.github.jan.supabase.auth.status.RefreshFailureCause import io.github.jan.supabase.auth.status.SessionSource import io.github.jan.supabase.auth.status.SessionStatus @@ -104,6 +105,35 @@ class AuthTest { } } + @Test + fun testBackgroundKeepsAuthenticatedStatusWhenResetDisabled() = runTest { + client = createMockedSupabaseClient(configuration = { + install(Auth) { + minimalConfig() + resetStatusOnBackground = false + } + }) + client.auth.awaitInitialization() + client.auth.importSession(userSession()) + assertIs(client.auth.sessionStatus.value) + client.auth.resetSessionStatusForBackground() + assertIs(client.auth.sessionStatus.value) + } + + @Test + fun testBackgroundResetsStatusToInitializingByDefault() = runTest { + client = createMockedSupabaseClient(configuration = { + install(Auth) { + minimalConfig() + } + }) + client.auth.awaitInitialization() + client.auth.importSession(userSession()) + assertIs(client.auth.sessionStatus.value) + client.auth.resetSessionStatusForBackground() + assertIs(client.auth.sessionStatus.value) + } + @Test fun testImportExpiredSession() { runTest {