Skip to content

fix(ios): derive openSecureWindow callbackURLScheme from redirectUri - #640

Open
kfarwell wants to merge 5 commits into
Cap-go:mainfrom
kfarwell:main
Open

fix(ios): derive openSecureWindow callbackURLScheme from redirectUri#640
kfarwell wants to merge 5 commits into
Cap-go:mainfrom
kfarwell:main

Conversation

@kfarwell

@kfarwell kfarwell commented Jul 21, 2026

Copy link
Copy Markdown

Currently openSecureWindow passes the authEndpoint's scheme (https) as callbackURLScheme to ASWebAuthenticationSession. Per Apple's documentation, callbackURLScheme must be the app's custom scheme for our session to intercept. This PR derives the callback scheme from redirectUri, falling back to the old url.scheme if it can't parse one.

http(s) works in practice only when the redirect scheme is registered in Info.plist, but this behaviour appears to be undocumented. With the fix, it is no longer necessary to add the scheme to Info.plist.

Issue reproduced and fix verified on iOS 26.5.

See: https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/init(url:callbackurlscheme:completionhandler:)-7fpox

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved in-app authentication redirect handling by deriving the callback scheme from the configured redirect URI.
    • Rejects invalid redirect URIs that can’t be parsed into a URL with a scheme.
    • Tightened callback validation by comparing URL components (including normalized path) and ensuring configured query parameters match in both presence and occurrence, while rejecting conflicts and injected authority/user info.
  • Tests
    • Added redirect-validation test coverage for ordering, duplicates, prefix-only matches, path/query encoding differences, and authority/port handling.

openSecureWindow passed the authEndpoint's scheme (generally https) to ASWebAuthenticationSession, but should be the app's custom scheme per Apple's spec.
@github-actions

Copy link
Copy Markdown
Contributor

Beta npm build

This PR comes from a fork, so beta publish is disabled for security.

If you need a beta package, move the branch into this repository first.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

openSecureWindow now derives the authentication callback scheme from redirectUri and rejects invalid redirect URIs. Callback validation compares URI components and configured query items while allowing additional provider query items, with focused XCTest coverage.

Changes

Secure window callback handling

Layer / File(s) Summary
Redirect URI matching and validation tests
ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift, ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift
Adds component-wise matching for scheme, host, port, user info, normalized path, and configured query items, replacing prefix validation. Tests cover query ordering, duplicates, provider parameters, URI boundaries, casing, ports, paths, user info, and invalid redirects.
Callback scheme selection
ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
openSecureWindow parses redirectUri, rejects invalid values, and uses its scheme for ASWebAuthenticationSession.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant openSecureWindow
  participant ASWebAuthenticationSession
  participant AuthProvider
  participant SecureWindowRedirectSupport
  openSecureWindow->>ASWebAuthenticationSession: start authentication with redirectUri scheme
  ASWebAuthenticationSession->>AuthProvider: authenticate
  AuthProvider-->>ASWebAuthenticationSession: redirect callback URL
  ASWebAuthenticationSession->>SecureWindowRedirectSupport: matches callback URL against redirectUri
  SecureWindowRedirectSupport-->>openSecureWindow: accept or reject callback
Loading

Suggested reviewers: riderx, cursor

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main iOS change: deriving openSecureWindow's callbackURLScheme from redirectUri.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated
@riderx

riderx commented Jul 21, 2026

Copy link
Copy Markdown
Member

Hello thanks for this, can you check the ai issues ?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift`:
- Around line 127-130: Update the query-parameter validation around
receivedItems so duplicate occurrences of configured parameter names are
rejected when their values conflict, including callbacks containing both
attacker-controlled and expected values. Preserve acceptance of unrelated
provider parameters and require each configured parameter to match
unambiguously.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2184c6cb-c8a2-456b-8874-da58bab521d4

📥 Commits

Reviewing files that changed from the base of the PR and between 0d469a0 and deaa8e1.

📒 Files selected for processing (1)
  • ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual) → reviewed against branch main instead of the default branch

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated
Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated
Compare the user and password components, and require the callback's query items under each configured name to match exactly, so a conflicting duplicate is rejected and repeated items are all required. Add tests for the matching rules.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift`:
- Line 126: Update the redirect path comparisons in the matching logic around
normalizedPath to use percentEncodedPath for both received and expected URLs,
preserving encoded path segments while retaining existing normalization. Add a
regression test covering callbacks with an encoded slash versus a literal slash
and ensure they do not match.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07c7a82a-b09a-4fa1-92d0-edf6abfbefb8

📥 Commits

Reviewing files that changed from the base of the PR and between deaa8e1 and 5605b9f.

📒 Files selected for processing (2)
  • ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
  • ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual) → reviewed against branch main instead of the default branch

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift Outdated
Compare percent-encoded and require repeated query items in order.

func testRejectsInjectedUserInfo() throws {
XCTAssertFalse(try matches("myapp://evil@callback?code=abc", "myapp://callback"))
XCTAssertFalse(try matches("https://evil:secret@example.com/callback", "https://example.com/callback"))

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

💡 Need a hand with PR review? Try Gitar by Sonar!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift (1)

15-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the “any order” test cover two configured items.

The redirect URI configures only type; code is an extra provider parameter. This does not verify that multiple configured query items can be reordered. Add a second configured item and assert the callback succeeds with those configured items reversed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift`
around lines 15 - 19, Update testAcceptsConfiguredQueryItemsInAnyOrder so the
configured redirect URI includes two query items, then assert matches succeeds
when the callback presents those configured items in reverse order while
retaining any extra provider parameter coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift`:
- Around line 15-19: Update testAcceptsConfiguredQueryItemsInAnyOrder so the
configured redirect URI includes two query items, then assert matches succeeds
when the callback presents those configured items in reverse order while
retaining any extra provider parameter coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 63a962c2-8ac5-4dc0-a12a-150293ca4398

📥 Commits

Reviewing files that changed from the base of the PR and between 5605b9f and cdd4623.

📒 Files selected for processing (2)
  • ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
  • ios/Tests/InAppBrowserPluginTests/SecureWindowRedirectSupportTests.swift
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual) → reviewed against branch main instead of the default branch

@kfarwell

Copy link
Copy Markdown
Author

Now matching scheme/user/password/host/port/path and query items configured in the redirect URI in SecureWindowRedirectSupport.matches() with tests. Components compared literally and repeated item order enforced. Redirect URIs with missing or unparseable schemes are rejected.

FYI looks like Android and web have the same startsWith issue.

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants