Skip to content

Allow headless application-password creation on Atomic sites#22885

Open
jkmassel wants to merge 1 commit into
jkmassel/issue-22884-list-screen-direct-hostfrom
jkmassel/issue-22884
Open

Allow headless application-password creation on Atomic sites#22885
jkmassel wants to merge 1 commit into
jkmassel/issue-22884-list-screen-direct-hostfrom
jkmassel/issue-22884

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

@jkmassel jkmassel commented May 21, 2026

Description

Fixes #22884.

Stacked PRs. This is the middle of a three-PR stack:

Problem

ApplicationPasswordsManager.getApplicationCredentials returned NotSupported for any site.isWPCom site. The guard was correct for Simple sites but blocked Atomic sites, which are also isWPCom-flagged and do support REST application-password creation. Users on Atomic saw the "Authenticate using Application Password" card on My Site and had to authorize through a Chrome Custom Tab even though the app could mint the credential on their behalf.

What changed

  1. Relax the FluxC guard (ApplicationPasswordsManager.kt:45): site.isWPComsite.isWPComSimpleSite. Atomic falls through to the existing origin == ORIGIN_WPCOM_REST branches and the Jetpack-tunnel JetpackApplicationPasswordsRestClient.

  2. Auto-mint before showing the card (ApplicationPasswordViewModelSlice + new SiteStore.createApplicationPassword): before rendering the "Authenticate" card, attempt headless creation via the FluxC manager. On success, persist credentials onto the SiteModel (so siteHasBadCredentials flips false) and skip the card. On failure, fall back to the existing discovery + Custom Tab card.

  3. Fix the launch crash (ApplicationPasswordsClientIdModule + SiteStore guard): the WordPress / Jetpack apps had never bound @ApplicationPasswordsClientId in their Dagger graphs, so any call into ApplicationPasswordsStore threw NoSuchElementException. This was latent — no production caller hit the path on these apps — until step 2 above started routing My Site through it and crashed the app on launch. Provide the binding with the same device-interpolated name the Custom Tab flow already uses ("Jetpack Android App on <device>" / "WordPress Android App on …"); also short-circuit SiteStore.createApplicationPassword to NotSupported when the configuration is disabled, so we degrade gracefully if the binding goes missing again.

  4. Validate-then-mint pipeline (new ApplicationPasswordValidator, slice restructure): collapse the previous isUsingSelfHostedRestApi → validate vs else → discovery+card split into a single uniform validate → mint → card flow that works for every site type.

    The validator hits users().retrieveMeWithViewContext() via WpApiClientProvider.getApplicationPasswordClient(site) (introduced in Route the application-passwords list screen through Basic auth #22894) — always Basic auth against the direct host. The previous validation went through getWpApiClient, which for Atomic returns the WPCom bearer client and never actually exercised the application password, so revoked passwords on Atomic were undetectable. On Invalid, the slice clears stored creds via a new SiteStore.deleteStoredApplicationPasswordCredentials and falls through to mint; on NetworkUnavailable, the card stays hidden.

    The mint step calls SiteStore.createApplicationPassword from item 2. The card step shows the reauth banner if we started with creds, the "authenticate" card otherwise — either way discovery still populates the Custom Tab URL.

    The XML-RPC-disabled card path is now gated on !isUsingWpComRestApi so it only fires for true self-hosted sites — Atomic and Jetpack-WPCom-REST sites talk REST end-to-end.

Site type coverage

Site type Today (trunk) After this PR
Atomic, no app pwd Card → Chrome Custom Tab Validate skipped → FluxC mint succeeds → no card
Atomic, valid app pwd No card No card (validation succeeds)
Jetpack-WPCom-REST, no app pwd Card → Chrome Custom Tab FluxC mint succeeds → no card
Simple WPCom No card (discovery empty) No card (FluxC mint NotSupported short-circuits)
Self-hosted with valid creds Validate path Same flow; validation now actually uses Basic auth
Self-hosted without creds Card → Chrome Custom Tab Same — mint Failure → discovery → card

The "revoke and recover" Atomic case is covered by #22893.

On-device verification

Confirmed against jeremyseriousbusinesstesting.wpcomstaging.com (Atomic):

  • Cold launch with no stored creds → FluxC mint succeeds → card hidden. ✅
  • Subsequent loads → validate succeeds → no card, no re-mint. ✅

Tests

Adds two FluxC manager cases (simple-WPCom NotSupported; Atomic Jetpack-tunnel mint) in ApplicationPasswordManagerTests, six slice cases in ApplicationPasswordViewModelSliceTest covering the new validate → mint → card flow, and a small standalone OnApplicationPasswordCreateErrorTest for the FluxC error class.

Testing instructions

The scenarios below are the ones this PR alone covers — they exercise the auto-mint and the happy-path validation. To test what happens when a server-side credential is revoked, when validation hits a transient error, or when the device is offline mid-validate, build from #22893 (PR3 is stacked on this PR and adds the validator hardening that makes those flows recoverable).

Atomic happy path — first foreground

  1. Sign in to Jetpack debug with a WP.com account that owns an Atomic site that does not have a pre-existing application password for this device.
  2. Open the Atomic site on My Site.
  • No "Authenticate using Application Password" card.
  • Logcat (adb logcat -s WordPress-MAIN | grep A_P:) shows Headless mint succeeded.
  • wp-admin → Users → Profile → Application Passwords shows a new entry named Jetpack Android App on <your device>.

Atomic — subsequent loads with valid creds

  1. After the happy path above, force-stop the app and reopen it.
  2. Open the same Atomic site on My Site.
  • No card.
  • Logcat shows A_P: Validation Success returned user id=... followed by Hiding card for ... - authenticated. No re-mint attempt.

Simple WPCom regression

  1. Switch to a Simple WPCom site on My Site.
  • No card. Logcat shows the mint returning NotSupported and discovery returning empty.

Self-hosted regression (true self-hosted, not Atomic)

  1. Self-hosted site with an existing app password:
  • Card hidden; validation uses Basic auth against the direct host.
  1. Self-hosted site without an app password:
  • Card appears; tapping still launches the Chrome Custom Tab authorize flow.

Out of scope here (covered by #22893)

These scenarios will not behave correctly against PR2 alone — the validator's classification still has the issues found during the initial on-device testing of this PR:

If you want to exercise the full revoke-and-recover flow on-device, build from the jkmassel/issue-22884-validator-hardening branch (or check out #22893's head).

Related

@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented May 21, 2026

1 Warning
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented May 21, 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
Build TypeDebug
Versionpr22885-cc93500
Build Number1488
Application IDorg.wordpress.android.prealpha
Commitcc93500
Installation URL1f6ri03jge7n8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented May 21, 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
Build TypeDebug
Versionpr22885-cc93500
Build Number1488
Application IDcom.jetpack.android.prealpha
Commitcc93500
Installation URL5ku5u814liv30
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 48.83721% with 88 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.33%. Comparing base (2828efe) to head (cc93500).

Files with missing lines Patch % Lines
...ava/org/wordpress/android/fluxc/store/SiteStore.kt 23.91% 35 Missing ⚠️
...pplicationpassword/ApplicationPasswordValidator.kt 3.57% 27 Missing ⚠️
...ationpassword/ApplicationPasswordViewModelSlice.kt 74.46% 7 Missing and 5 partials ⚠️
...word/ApplicationPasswordAutoAuthDialogViewModel.kt 25.00% 4 Missing and 2 partials ⚠️
...i/accounts/login/ApplicationPasswordLoginHelper.kt 85.71% 0 Missing and 4 partials ⚠️
...npassword/LoginSiteApplicationPasswordViewModel.kt 33.33% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@                               Coverage Diff                                @@
##           jkmassel/issue-22884-list-screen-direct-host   #22885      +/-   ##
================================================================================
+ Coverage                                         37.32%   37.33%   +0.01%     
================================================================================
  Files                                              2320     2321       +1     
  Lines                                            124580   124644      +64     
  Branches                                          16926    16938      +12     
================================================================================
+ Hits                                              46498    46538      +40     
- Misses                                            74321    74342      +21     
- Partials                                           3761     3764       +3     

☔ 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.

@wpmobilebot
Copy link
Copy Markdown
Contributor

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

@jkmassel jkmassel force-pushed the jkmassel/issue-22884 branch 2 times, most recently from 1888111 to 912dd2e Compare May 25, 2026 17:44
@jkmassel jkmassel force-pushed the jkmassel/issue-22884 branch from 912dd2e to a123523 Compare May 25, 2026 17:56
@jkmassel jkmassel changed the base branch from trunk to jkmassel/issue-22884-list-screen-direct-host May 25, 2026 17:58
@jkmassel jkmassel added this to the 26.8 milestone May 25, 2026
@jkmassel jkmassel requested a review from adalpari May 25, 2026 18:51
Fixes #22884.

`ApplicationPasswordsManager.getApplicationCredentials` returned `NotSupported` for any
`site.isWPCom` site. The guard was correct for Simple sites but blocked Atomic sites, which
are also `isWPCom`-flagged and do support REST application-password creation. Users on Atomic
saw the "Authenticate using Application Password" card on My Site and had to authorize through
a Chrome Custom Tab even though the app could mint the credential on their behalf.

Relax the FluxC guard from `site.isWPCom` to `site.isWPComSimpleSite` and add a uniform
validate-then-mint pipeline to `ApplicationPasswordViewModelSlice`: validate stored creds via
wordpress-rs Basic auth against the direct host (new `ApplicationPasswordValidator`, using
`WpApiClientProvider.getApplicationPasswordClient` from #22894); on Invalid, clear them via a
new `SiteStore.deleteStoredApplicationPasswordCredentials` and fall through to mint via a new
`SiteStore.createApplicationPassword` (FluxC Jetpack tunnel); on mint failure, the existing
discovery + card path takes over. The XML-RPC-disabled card path is now gated on
`!isUsingWpComRestApi` so it only fires for true self-hosted sites.

Also provides the missing `@ApplicationPasswordsClientId` Dagger binding — without it any call
into `ApplicationPasswordsStore` threw `NoSuchElementException`. The path was latent on these
apps until the auto-mint above started routing My Site through it.
@jkmassel jkmassel force-pushed the jkmassel/issue-22884 branch from dc9ff28 to cc93500 Compare May 25, 2026 19:10
@jkmassel jkmassel marked this pull request as ready for review May 25, 2026 19:12
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.

Allow headless application-password creation on Atomic sites

3 participants