Skip to content

fix: open redirect_to URL in browser to prevent infinite deep link loop#22648

Open
dcalhoun wants to merge 2 commits intotrunkfrom
fix/prevent-infinite-passwordless-login-loop
Open

fix: open redirect_to URL in browser to prevent infinite deep link loop#22648
dcalhoun wants to merge 2 commits intotrunkfrom
fix/prevent-infinite-passwordless-login-loop

Conversation

@dcalhoun
Copy link
Member

@dcalhoun dcalhoun commented Mar 3, 2026

Description

Fix CMM-1230. Fix NL-473.

When the Jetpack app receives a public-api.wordpress.com/bar/ or /mbar/ tracking URL (e.g. from a WordPress passwordless login email), it extracts the redirect_to parameter and tries to handle the destination in-app. If no handler exists for the destination (e.g. wordpress.com/log-in/link/use for passwordless login), the fallback opens the original tracking URL in the browser.

This causes an infinite loop on Play Store builds. The exact interception mechanism is unclear — the app's intent filter uses pathPattern="/bar/.*" which shouldn't match /bar/ with no trailing path segment, and local debug builds don't reproduce the issue. It may be related to Android App Links verification behaving differently for Play Store installs, or the server-side 302 redirect from /bar to /bar/ interacting with the verified domain. Regardless, the app repeatedly cycles between trying to handle the URL and falling back to the browser.

This PR changes the fallback in buildNavigateAction() so that when a tracking URL's redirect_to target can't be handled in-app, it opens the extracted redirect_to URL in the browser instead of the original tracking URL. This breaks the loop because the redirect destination (e.g. wordpress.com/log-in/link/use) is not matched by any of the app's intent filters.

When there is no redirect_to parameter at all, the existing behavior (open tracking URL with bar path in browser) is preserved.

Testing instructions

Passwordless login flow:

  1. Uninstall previous apps, install the PR's prototype build.
  2. In the app, log in with a password-less WordPress.com account.
  3. Finish the log in process in the browser that launches.
  4. Tap Approve for the OAuth connection in the browser UI.
  • Verify the app launches and the user is logged into the app.

When a tracking URL's redirect_to target can't be handled in-app, open
the extracted redirect_to URL in the browser instead of the original
tracking URL. This prevents an infinite loop caused by the app's intent
filter re-intercepting its own public-api.wordpress.com/bar/ URLs.
@wpmobilebot
Copy link
Contributor

wpmobilebot commented Mar 3, 2026

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
FlavorJalapeno
Build TypeDebug
Versionpr22648-11b4f31
Build Number1485
Application IDcom.jetpack.android.prealpha
Commit11b4f31
Installation URL6ss6dap2mfo60
Note: Google Login is not supported on these builds.

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Mar 3, 2026

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
FlavorJalapeno
Build TypeDebug
Versionpr22648-11b4f31
Build Number1485
Application IDorg.wordpress.android.prealpha
Commit11b4f31
Installation URL6b13c29rhv19o
Note: Google Login is not supported on these builds.

@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 38.11%. Comparing base (dd30b6b) to head (11b4f31).
⚠️ Report is 3 commits behind head on trunk.

Additional details and impacted files
@@           Coverage Diff           @@
##            trunk   #22648   +/-   ##
=======================================
  Coverage   38.11%   38.11%           
=======================================
  Files        2263     2263           
  Lines      115857   115862    +5     
  Branches    16100    16102    +2     
=======================================
+ Hits        44157    44162    +5     
  Misses      68075    68075           
  Partials     3625     3625           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dcalhoun dcalhoun added this to the 26.7 milestone Mar 3, 2026
@dcalhoun dcalhoun marked this pull request as ready for review March 3, 2026 18:23
@dcalhoun dcalhoun requested a review from jkmassel March 3, 2026 18:23
Copy link
Contributor

@jkmassel jkmassel left a comment

Choose a reason for hiding this comment

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

This seems like it cleanly addresses the issue.

@adalpari, could you also take a look since I know you're at least a little familiar with deep links?

@dcalhoun – WDYT about targeting the release branch for this?

@dcalhoun
Copy link
Member Author

dcalhoun commented Mar 3, 2026

@dcalhoun – WDYT about targeting the release branch for this?

@jkmassel given how disruptive this bug is, it's likely worth including in the release branch. That said, I welcome testing by the team to reduce the likelihood of regressions.

@dcalhoun dcalhoun requested a review from adalpari March 4, 2026 02:43
When a tracking URL's redirect_to target can't be handled in-app, the
app now opens the redirect destination in the browser (loop fix) but
the server never sees the original tracking URL. Fire the pixel
explicitly in this path so email link taps are still recorded.

The no-redirect fallback still opens /bar/ in the browser, which
handles tracking implicitly via the browser's HTTP request.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 4, 2026

@dcalhoun
Copy link
Member Author

dcalhoun commented Mar 4, 2026

I pushed a change, so we'll need to await a new prototype build before testing again.

Copy link
Contributor

@adalpari adalpari left a comment

Choose a reason for hiding this comment

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

Thank you for the fix! LGTM and works as expected!

@adalpari
Copy link
Contributor

adalpari commented Mar 4, 2026

I pushed a change, so we'll need to await a new prototype build before testing again.

Ops, just saw this. Is the new prototype ready?

@dcalhoun
Copy link
Member Author

dcalhoun commented Mar 4, 2026

Noting that I tested a few different emails. All showcased the loop in trunk; all were addressed by this change.

  • "Log in to WordPress.com" after submitting the login form with a password less account; tapping the "Log in now" button.
  • "Welcome to <site>!" email after substring to a site in Reader web; tapping the Manage subscriptions button.
  • "<name> accepted your invitation" email after someone accepts your invite to a site; tapping the Manage users button.
  • Send test post email (image below) from draft post; tapping the Comment button.
Screenshot 2026-03-04 at 09 56 52

@dcalhoun
Copy link
Member Author

dcalhoun commented Mar 4, 2026

I pushed a change, so we'll need to await a new prototype build before testing again.

Ops, just saw this. Is the new prototype ready?

@adalpari it's been ready for a while (~2 hours), so likely not an issue. The only way to confirm is to navigate to Me → About Jetpack in the installed app and verifying the version commit/build number matches the latest in #22648 (comment).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants