From cd7c2fbcaf9b8817ce942244915e3528b758677b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 18 Aug 2026 22:33:16 -0700 Subject: [PATCH 1/3] fix(expo): fire AuthView onDismiss when isDismissible is false on iOS The iOS bridge only reported a dismissal when the view was dismissible, so a non-dismissible AuthView never told JS the auth flow had finished and an app-owned modal stayed open after sign-in. Android already fires onAuthComplete regardless. Wires the new clerkAuthCompletionAction SPI from clerk-ios into the hosted auth view, ungated by dismissibility. The detach path keeps its dismissible check, since a non-dismissible view never self-dismisses and a detach there is the host tearing the view down. --- .../expo-authview-ondismiss-non-dismissible.md | 5 +++++ packages/expo/ios/ClerkAuthNativeView.swift | 13 ++++++++----- packages/expo/ios/ClerkNativeBridge.swift | 4 ++++ 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .changeset/expo-authview-ondismiss-non-dismissible.md diff --git a/.changeset/expo-authview-ondismiss-non-dismissible.md b/.changeset/expo-authview-ondismiss-non-dismissible.md new file mode 100644 index 00000000000..7c5fbe99812 --- /dev/null +++ b/.changeset/expo-authview-ondismiss-non-dismissible.md @@ -0,0 +1,5 @@ +--- +'@clerk/expo': patch +--- + +Fix `AuthView`'s `onDismiss` never firing on iOS when `isDismissible` is `false`. The callback now runs once the auth flow completes, matching Android, so an app-owned modal or screen wrapping the view can close after sign-in. diff --git a/packages/expo/ios/ClerkAuthNativeView.swift b/packages/expo/ios/ClerkAuthNativeView.swift index e76a8be1b1c..5f8d2ba66d5 100644 --- a/packages/expo/ios/ClerkAuthNativeView.swift +++ b/packages/expo/ios/ClerkAuthNativeView.swift @@ -44,9 +44,8 @@ public class ClerkAuthNativeView: ClerkNativeViewHost { onAuthEvent(["type": type.rawValue]) } - private func sendDismissIfNeeded() { - // SwiftUI dismissals detach the hosted view without calling UIKit dismiss(). - guard currentDismissible, !didSendDismiss else { return } + private func sendDismiss() { + guard !didSendDismiss else { return } didSendDismiss = true sendAuthEvent(type: .dismissed) } @@ -56,7 +55,11 @@ public class ClerkAuthNativeView: ClerkNativeViewHost { } override func hostedViewDidDetachFromWindow() { - sendDismissIfNeeded() + // SwiftUI dismissals detach the hosted view without calling UIKit dismiss(). + // A non-dismissible view never self-dismisses, so a detach there is the host + // tearing the view down rather than a dismissal to report. + guard currentDismissible else { return } + sendDismiss() } override public func layoutSubviews() { @@ -119,7 +122,7 @@ public class ClerkAuthNativeView: ClerkNativeViewHost { hostBackAction: hostBackAction, onEvent: { [weak self] event, _ in if event == .dismissed { - self?.sendDismissIfNeeded() + self?.sendDismiss() } } ) diff --git a/packages/expo/ios/ClerkNativeBridge.swift b/packages/expo/ios/ClerkNativeBridge.swift index 57fbbb92013..ed5b892b1d9 100644 --- a/packages/expo/ios/ClerkNativeBridge.swift +++ b/packages/expo/ios/ClerkNativeBridge.swift @@ -958,6 +958,10 @@ final class ClerkNativeBridge { darkTheme: darkTheme, logoState: logoState, logoMaxHeight: logoMaxHeight + ) + .environment( + \.clerkAuthCompletionAction, + ClerkAuthCompletionAction { onEvent(.dismissed, [:]) } ), onDismiss: dismissible ? { onEvent(.dismissed, [:]) } : nil ) From dbc20727b750f67c52fbf9c3bfc089541290af87 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 18 Aug 2026 23:20:45 -0700 Subject: [PATCH 2/3] fix(expo): isolate makeAuthViewController to the main actor Constructing ClerkAuthCompletionAction, which is @MainActor, from a nonisolated context failed to compile. The neighbouring makeUserProfileViewController was already annotated, and the caller in ClerkNativeViewHost is main-actor isolated via UIView, so this brings the two factory methods back in line. --- packages/expo/ios/ClerkNativeBridge.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/expo/ios/ClerkNativeBridge.swift b/packages/expo/ios/ClerkNativeBridge.swift index ed5b892b1d9..382bb210b4e 100644 --- a/packages/expo/ios/ClerkNativeBridge.swift +++ b/packages/expo/ios/ClerkNativeBridge.swift @@ -939,6 +939,7 @@ final class ClerkNativeBridge { // MARK: - Inline View Creation + @MainActor func makeAuthViewController( mode: String, dismissible: Bool, From c7a5c09883ad7da4b6be0aaa5e88a565e0beb499 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 19 Aug 2026 09:29:44 -0700 Subject: [PATCH 3/3] fix(expo): adopt the renamed ClerkAuthFlowCompletionAction SPI --- packages/expo/ios/ClerkNativeBridge.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/expo/ios/ClerkNativeBridge.swift b/packages/expo/ios/ClerkNativeBridge.swift index 382bb210b4e..002b44d517b 100644 --- a/packages/expo/ios/ClerkNativeBridge.swift +++ b/packages/expo/ios/ClerkNativeBridge.swift @@ -961,8 +961,8 @@ final class ClerkNativeBridge { logoMaxHeight: logoMaxHeight ) .environment( - \.clerkAuthCompletionAction, - ClerkAuthCompletionAction { onEvent(.dismissed, [:]) } + \.clerkAuthFlowCompletionAction, + ClerkAuthFlowCompletionAction { onEvent(.dismissed, [:]) } ), onDismiss: dismissible ? { onEvent(.dismissed, [:]) } : nil )