diff --git a/Sources/LaunchFeature/LaunchController.swift b/Sources/LaunchFeature/LaunchController.swift
index 2684c669cd4860ec49c7efebba6abba9ea138fd4..8a9b10717cf85e70c0bd20ee2581e1e79898ecca 100644
--- a/Sources/LaunchFeature/LaunchController.swift
+++ b/Sources/LaunchFeature/LaunchController.swift
@@ -27,7 +27,7 @@ public final class LaunchController: UIViewController {
       .statePublisher
       .receive(on: DispatchQueue.main)
       .sink { [unowned self] in
-        guard $0.shouldPushChats == false else {
+        guard $0.shouldPushEndDestination != .some(.chats) else {
           guard $0.shouldShowTerms == false else {
             navigator.perform(PresentTermsAndConditions(replacing: true, on: navigationController!))
             return
@@ -39,7 +39,7 @@ public final class LaunchController: UIViewController {
           navigator.perform(PresentChatList(on: navigationController!))
           return
         }
-        guard $0.shouldPushOnboarding == false else {
+        guard $0.shouldPushEndDestination != .some(.onboarding) else {
           navigator.perform(PresentOnboardingStart(on: navigationController!))
           return
         }
diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift
index bbb68e5dc47560b8542113565e198eb12c96e1bf..732d2e2dd3bd4155d0b10376f17ac8e20af75c2b 100644
--- a/Sources/LaunchFeature/LaunchViewModel.swift
+++ b/Sources/LaunchFeature/LaunchViewModel.swift
@@ -29,6 +29,10 @@ import class XXClient.Cancellable
 import PulseLogHandler
 
 final class LaunchViewModel {
+  enum Destination {
+    case chats, onboarding
+  }
+
   struct UpdateModel {
     let content: String
     let urlString: String
@@ -39,9 +43,8 @@ final class LaunchViewModel {
 
   struct ViewState {
     var shouldShowTerms = false
-    var shouldPushChats = false
     var shouldOfferUpdate: UpdateModel?
-    var shouldPushOnboarding = false
+    var shouldPushEndDestination: Destination?
   }
 
   @Dependency(\.app.log) var log
@@ -202,21 +205,41 @@ extension LaunchViewModel {
 
     try dummyTrafficManager.setStatus(dummyTrafficOn)
 
+    let endDestination: Destination
+
     if messenger.isLoggedIn() == false {
       if try messenger.isRegistered() {
         try messenger.logIn()
-        hudManager.hide()
-        stateSubject.value.shouldPushChats = true
+        endDestination = .chats
       } else {
         try? sftpManager.unlink()
         try? dropboxManager.unlink()
-        hudManager.hide()
-        stateSubject.value.shouldPushOnboarding = true
+        endDestination = .onboarding
       }
     } else {
+      endDestination = .chats
+    }
+
+    defer {
       hudManager.hide()
-      stateSubject.value.shouldPushChats = true
+      if endDestination == .chats {
+        if isBiometricsOn, permissions.biometrics.status() {
+          permissions.biometrics.request { [weak self] granted in
+            guard let self else { return }
+            if granted {
+              self.stateSubject.value.shouldPushEndDestination = .chats
+            } else {
+              // TODO: A fallback state for failing biometrics
+            }
+          }
+        } else {
+          stateSubject.value.shouldPushEndDestination = .chats
+        }
+      } else {
+        stateSubject.value.shouldPushEndDestination = .onboarding
+      }
     }
+
     if !messenger.isBackupRunning() {
       try? messenger.resumeBackup()
     }