iOS: redirect after a failed authorize() crashes the app (finished session kept as _currentSession)
評価
- 難易度
- 3/5
- 見積もり時間
- 半日
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- ios, objective-c, react-native, swift
- 領域
- authentication, mobile
調査の方向性
Start in packages/react-native-app-auth/ios/RNAppAuth.m: read authorizeWithConfiguration: where _currentSession is assigned, the completion block that clears it, and resumeExternalUserAgentFlowWithURL: near the top of the file. The author has already announced a fix and PR, so check for an open PR before starting. Done means a redirect that arrives after a failed authorize() no longer reaches a finished AppAuth session. This needs an iOS simulator with Xcode to verify.
索引モデルが issue の本文から書いたものです。
説明
Issue
When authorize() or logout() fails synchronously on iOS (the browser could not be opened), the native module keeps the failed AppAuth session as _currentSession. Any URL that later matches the redirect URL is forwarded to that finished session. With AppAuth 2.0.0 this terminates the app with an uncaught Objective-C exception:
An OAuth redirect was sent to a OIDExternalUserAgentSession after it already completed.
-[OIDAuthorizationSession resumeExternalUserAgentFlowWithURL:] (OIDAuthorizationService.m:135)
-[RNAppAuth resumeExternalUserAgentFlowWithURL:] (RNAppAuth.m:20)
AppDelegate.application(_:open:options:) (AppDelegate.swift:51)
It is an NSException, so a Swift AppDelegate cannot catch it.
This is the same exception and stack as #1080, with a different trigger. I have not reproduced the #1080 trigger myself.
Reproduction with examples/demo on the simulator
main at 93d06bc, AppAuth 2.0.0 as pinned by examples/demo/ios/Podfile.lock, Xcode 26.3, iPhone 17 Pro simulator on iOS 26.1.
- In
examples/demo/App.tsx, addiosCustomBrowser: 'chrome'to the options passed toauthorize(). - In
examples/demo/ios/Example/Info.plist, addgooglechromestoLSApplicationQueriesSchemes(AppAuth asserts on this in debug builds). - Run the app on a simulator, where Chrome is not installed, and tap Login with IdentityServer. An alert appears: "Failed to log in",
Unable to open Safari. - Dismiss the alert, then deliver a URL that matches the redirect URL:
xcrun simctl openurl booted "io.identityserver.demo:/oauthredirect?code=x&state=y"
- The app crashes with the stack above.
code and state are dummy values on purpose: the app crashes before either of them is read.
How I hit it in a production app
authorize() with iosCustomBrowser: 'safari', on an iPhone where Safari is disabled (Settings > Screen Time > Content & Privacy Restrictions > Allowed Apps) and Chrome is the default browser:
- Chrome opens with the login page, but the promise has already been rejected with
Unable to open Safari. - The user logs in and Chrome redirects to the app's custom scheme.
- The app is terminated with the exception above.
With Safari enabled the same flow works. Why AppAuth reports a failure although a browser did open is a separate problem in AppAuth's custom browser user-agent, which I will report to openid/AppAuth-iOS. Here it is only the trigger.
Cause
Links are to main at 93d06bc and to AppAuth 2.0.0.
authorizeWithConfiguration:stores the session returned by AppAuth (RNAppAuth.m#L441-L443).- AppAuth presents the session before returning it. If presenting fails, it completes the session and invokes the callback synchronously, before that call returns (
OIDAuthorizationService.m#L74-L86, throughOIDAuthState.m#L167-L169). - The callback clears
_currentSession(RNAppAuth.m#L426-L427). Then the call from step 1 returns, and the assignment puts the finished session back. - From then on, every URL that reaches the app delegate is forwarded to that session (
RNAppAuth.m#L19-L21). AppAuth accepts the URL if scheme, host and path match the redirect URL (the query is ignored), finds no pending callback and raises (OIDAuthorizationService.m#L123-L135).
The other authorize branches and logout follow the same pattern.
There is a second way to reach the same exception, which I found by reading the code and have not reproduced: _currentSession stays set until the code exchange finishes, while the AppAuth session is already complete once it has consumed the redirect. A second matching URL that arrives during the token request is forwarded to a finished session too.
AppAuth versions
AppAuth 2.1.0 replaced the exception with a NO return value (openid/AppAuth-iOS#955), so the crash needs AppAuth < 2.1.0. The podspec accepts AppAuth >= 1.7.6, and a project that already has 2.0.0 in its Podfile.lock keeps it until pod update. Holding on to a finished session looks wrong on any version, so I think it is worth fixing here as well.
I have a fix ready and will open a PR right after this issue.
Environment
- Your Identity Provider:
Keycloak(production app); the Duende demo server configured inexamples/demo(simulator reproduction) - Platform that you're experiencing the issue on:
iOS - Your
react-nativeVersion:0.82.1(production app, new architecture, Swift AppDelegate);0.79.2(examples/demo) - Your
react-native-app-authVersion:8.4.1(production app);mainat 93d06bc, i.e. 8.5.0 (examples/demo) - Are you using Expo? No
- AppAuth pod:
2.0.0in both - Device (production app): Apple iPhone 15 iOS: 27.0
- 主要言語
- Java
- スター
- 2.3k
- フォーク
- 472
- 平均マージ
- 3日 7時間
- マージ済み PR(30日)
- 3
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
FormidableLabs/react-native-app-auth のほかの issue
-
[Android] AuthorizationService is never disposed: Custom Tabs bind leak breaks refresh() permanently after ~1000 calls対応中かも @pranshuchittora が 66 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 62/100
-
Android: opt-in Partial Custom Tab (bottom-sheet) for the authorization flow対応中かも @omeratt が 146 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
FormidableLabs/react-native-app-auth#1108 · コメント 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 28/100
FormidableLabs/react-native-app-auth の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
apache/rocketmq-dashboard#6872 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
ADORSYS-GIS/token-status-link#168 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
ADORSYS-GIS/keycloak-oid4vp-plugin#232 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 2 日以内に返信
-
documentation
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
devops-thiago/ThrillhouseBot#1132 ·
メンテナーはふだん 1 日以内に返信