Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Custom browser user-agent fails the flow with "Unable to open Safari." while the browser opens (it returns the result of canOpenURL:)

オープン
#980 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

@federicobartoli がすでに取り組んでいます。

2026年10月9日 から。

  • #981 @federicobartoli による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
25/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
ios, objective-c

調査の方向性

The change belongs in presentExternalUserAgentRequest:session: in Sources/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.m, which currently returns the result of canOpenURL:. Sources/AppAuthCore/OIDAuthorizationService.m shows where the session fails with OIDErrorCodeSafariOpenError. Linked PR #981 is already open against this issue, so review it before starting. Done means the method reports presentation as started and fails the session only when the open completion handler reports failure.

索引モデルが issue の本文から書いたものです。

説明

bug triage

Describe the bug

-[OIDExternalUserAgentIOSCustomBrowser presentExternalUserAgentRequest:session:] returns the result of canOpenURL: but calls openURL:options:completionHandler: regardless of it (OIDExternalUserAgentIOSCustomBrowser.m#L153-L158).

When canOpenURL: answers NO for a URL that the system can in fact open, the browser opens and the user can sign in, but the session has already been failed with OIDErrorCodeSafariOpenError, "Unable to open Safari." (OIDAuthorizationService.m#L78-L85). The redirect that comes back afterwards has no pending flow to resume, so the sign-in cannot complete.

To Reproduce

On an iPhone with Chrome installed and set as the default browser, in an app that does not list https under LSApplicationQueriesSchemes:

  1. Disable Safari: Settings > Screen Time > Content & Privacy Restrictions > Allowed Apps > Safari off.
  2. Start an authorization request with [OIDExternalUserAgentIOSCustomBrowser CustomBrowserSafari].
  3. Chrome opens with the authorization page. At the same time the authorization callback is invoked with OIDErrorCodeSafariOpenError, "Unable to open Safari."
  4. Complete the sign-in in Chrome. The redirect reaches a session that has already completed. With AppAuth 2.0.0 this raises OIDOAuthExceptionInvalidAuthorizationFlow and the app is terminated.

What I measured on the device, for the provider's https URL:

Safari https in LSApplicationQueriesSchemes canOpenURL: Sign-in
enabled no YES works
disabled no NO fails as described, although Chrome opens
disabled yes YES works

The canOpenURL: values were read through React Native's Linking.canOpenURL, which calls -[UIApplication canOpenURL:].

Expected behavior

The request is reported as presented, because the browser did open. The session stays pending until the redirect arrives, and fails only if the URL really could not be opened.

Screenshots

Not applicable.

Environment

  • Device: iPhone 15
  • OS: iOS 27.0.1
  • Browser: Chrome as the default browser, Safari disabled through Screen Time
  • AppAuth 2.0.0 via CocoaPods, used through react-native-app-auth 8.4.1. OIDExternalUserAgentIOSCustomBrowser.m is unchanged in 2.1.0, 3.0.0 and on master.

Additional context

Cause. canOpenURL: is a prediction with its own preconditions. Apple's documentation says it returns false "if you haven't declared the URL's scheme in your Info.plist file", and that open(_:options:completionHandler:) "isn't constrained by the LSApplicationQueriesSchemes requirement. If an app is available to handle the URL, the system will launch it, even if you haven't declared the scheme." A true result guarantees that the open will succeed; a false result does not mean it will fail. I reported the inconsistent answer for https to Apple as FB25124433.

History. Until 1.7.5 this method returned the result of the synchronous -[UIApplication openURL:], that is, the real outcome. #871 (released in 1.7.6) replaced the deprecated call and returned the result of canOpenURL: instead, and #911 kept that.

Later versions. #955 (2.1.0) replaced the exception with an error return, so step 4 no longer crashes there. I have only run 2.0.0, but from the code the session is failed in the same way on 2.1.0 and 3.0.0, so the sign-in still cannot complete.

Proposed fix. Report the presentation as started and fail the session only if the open really fails, using the completion handler. The error code and message stay the same.

--- a/Sources/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.m
+++ b/Sources/AppAuth/iOS/OIDExternalUserAgentIOSCustomBrowser.m
@@ -27,6 +27,7 @@
 #import "OIDAuthorizationRequest.h"
 #import "OIDAuthorizationService.h"
 #import "OIDErrorUtilities.h"
+#import "OIDExternalUserAgentSession.h"
 #import "OIDURLQueryComponent.h"
 
 #if !TARGET_OS_MACCATALYST
@@ -153,9 +154,24 @@ NS_ASSUME_NONNULL_BEGIN
   // Transforms the request URL and opens it.
   NSURL *requestURL = [request externalUserAgentRequestURL];
   requestURL = _URLTransformation(requestURL);
-  BOOL willOpen = [[UIApplication sharedApplication] canOpenURL:requestURL];
-  [[UIApplication sharedApplication] openURL:requestURL options:@{} completionHandler:nil];
-  return willOpen;
+  if (!requestURL) {
+    return NO;
+  }
+  // -canOpenURL: is not used to decide whether the request was presented: it is subject to
+  // LSApplicationQueriesSchemes and can return NO for a URL that
+  // -openURL:options:completionHandler: opens successfully (e.g. an https URL when Safari is
+  // unavailable and another browser is the default). The flow fails only if the open really fails.
+  [[UIApplication sharedApplication] openURL:requestURL
+                                     options:@{}
+                           completionHandler:^(BOOL success) {
+    if (!success) {
+      NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
+                                              underlyingError:nil
+                                                  description:@"Unable to open Safari."];
+      [session failExternalUserAgentFlowWithError:safariError];
+    }
+  }];
+  return YES;
 }

I tested this change on the device above, applied to AppAuth 2.0.0, with Safari disabled and without the https declaration, so canOpenURL: still returned NO: Chrome opens, the session stays pending and the sign-in completes.

The only observable change for a real failure is timing: the same error is delivered from the completion handler instead of synchronously through the NO return value. The "browser not installed, open the App Store" branch is untouched.

Workaround for integrators. Adding https to LSApplicationQueriesSchemes makes canOpenURL: return YES in this situation.

I am aware the README describes this user-agent as not intended for consumer apps. The change restores what the method reported before 1.7.6, and apps that have to return to the same browser after a hand-off to a separate authenticator app have no other built-in user-agent to use. I'm happy to open a PR for it.

Downstream report: FormidableLabs/react-native-app-auth#1151.

主要言語
Objective-C
スター
2k
フォーク
866
平均マージ
9日 20時間
マージ済み PR(30日)
1

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

openid/AppAuth-iOS のほかの issue

openid/AppAuth-iOS の issue をすべて見る

似ている issue

Objective-C の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。