Skip to content

Route the application-passwords list screen through Basic auth#22894

Open
jkmassel wants to merge 2 commits into
trunkfrom
jkmassel/issue-22884-list-screen-direct-host
Open

Route the application-passwords list screen through Basic auth#22894
jkmassel wants to merge 2 commits into
trunkfrom
jkmassel/issue-22884-list-screen-direct-host

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

Fixes a bug where the application-passwords list screen returned an empty list / auth error on Atomic sites. Targets trunk directly so it can land independently — the larger Atomic headless mint work (#22885) builds on top of this.

Supersedes #22892, which was auto-closed during a branch reshuffle when its diff against its (then-)base became empty.

Summary

  • Add WpApiClientProvider.getApplicationPasswordClient(site) — always returns a direct-host Basic-auth client built from the SiteModel's application-password credentials, regardless of WP.com routing.
  • Swap getWpApiClient(site)getApplicationPasswordClient(site) in ApplicationPasswordsViewModel.kt.

Root Cause

getWpApiClient routes WPCom-flagged sites (including Atomic) through the WP.com REST proxy at https://public-api.wordpress.com/rest/v1.1/sites/{id}/wp/v2/.... The proxy doesn't expose the application-passwords routes — every request 404s with rest_no_route. This is the same upstream wordpress-rs limitation (Automattic/wordpress-rs#1350) that drove dropping the headless wordpress-rs mint attempt in #22885.

Fix

The new method getApplicationPasswordClient always reuses the selfHostedClients cache path — Basic auth against the direct host using the SiteModel's apiRestUsernamePlain / apiRestPasswordPlain. The direct host serves the application-passwords routes on every WordPress install.

For self-hosted sites the behaviour is unchanged: both getWpApiClient and getApplicationPasswordClient end up returning the same Basic-auth client via selfHostedClients.getOrPut(site.id). For Atomic and Jetpack-WPCom-REST sites the change is what matters — we now bypass the proxy and talk to the underlying WordPress install directly.

Limitations

The SiteModel must already have application-password credentials. On a Simple WPCom site there are no such credentials and the call will 401 — but that screen isn't really meant to work on Simple sites anyway. For Atomic sites, the credentials are populated by the My Site auto-mint flow once #22885 lands; in the meantime, users on Atomic still need to authorize the first time via the Custom Tab flow.

Test plan

  • Open an Atomic site → Me → Application Passwords. List displays correctly.
  • Open a self-hosted site with stored creds → Me → Application Passwords. List displays correctly (regression check).
  • Delete an app password server-side → re-open the screen. Error message surfaces correctly.

Related

jkmassel added 2 commits May 25, 2026 11:51
Companion to `getWpApiClient` that always returns a direct-host
Basic-auth client built from the SiteModel's application-password
credentials, regardless of WP.com routing. `getWpApiClient` sends
WPCom-flagged sites (including Atomic) through the bearer-token
path and the WP.com REST proxy, which doesn't expose all of the
application-password-authenticated routes. The list-screen change
in the next commit needs to talk to the direct host; the auto-mint
+ validator work in the headless-creation PR uses this same method.
`ApplicationPasswordsViewModel.getApplicationPasswordsList` called
`WpApiClientProvider.getWpApiClient(site)`, which for any WPCom-flagged
site (including Atomic) routes through the WP.com REST proxy. That
proxy doesn't expose the `application-passwords` routes — every
request 404s with `rest_no_route`, the same upstream wordpress-rs
limitation that drove dropping the headless mint attempt in this
project (Automattic/wordpress-rs#1350). As a result, the list screen
appeared empty / errored on Atomic sites: `getCurrentUserId` would
404, return null, and `getApplicationPasswordsList` would early-return
an empty list.

Switch to `WpApiClientProvider.getApplicationPasswordClient(site)`,
which always builds a direct-host Basic-auth client from the stored
application-password credentials. The direct host serves the
`application-passwords` routes on every WordPress install, so the
listing call works for Atomic and Jetpack-WPCom-REST sites in
addition to true self-hosted.

For self-hosted, behavior is unchanged: both client providers route
self-hosted sites through `selfHostedClients.getOrPut(site.id) {
createSelfHostedClient(site, ...) }`, returning the same Basic-auth
client.

Precondition: the SiteModel must already have credentials —
typically populated by the My Site auto-mint flow on first foreground.
A user reaching the list screen without ever visiting My Site would
401 instead of seeing an empty screen. That edge case can be handled
separately (e.g. by minting on demand here) and is out of scope.
@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented May 25, 2026

1 Warning
⚠️ This PR is assigned to the milestone 26.8. The due date for this milestone has already passed.
Please assign it to a milestone with a later deadline or check whether the release for this milestone has already been finished.

Generated by 🚫 Danger

@jkmassel jkmassel requested review from adalpari and nbradbury and removed request for nbradbury May 25, 2026 18:02
@jkmassel jkmassel self-assigned this May 25, 2026
@jkmassel jkmassel modified the milestones: 26.9, 26.8 May 25, 2026
@jkmassel jkmassel marked this pull request as ready for review May 25, 2026 18:03
@wpmobilebot
Copy link
Copy Markdown
Contributor

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
Versionpr22894-2828efe
Build Number1488
Application IDorg.wordpress.android.prealpha
Commit2828efe
Installation URL0kdfhjgs8h58g
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

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
Versionpr22894-2828efe
Build Number1488
Application IDcom.jetpack.android.prealpha
Commit2828efe
Installation URL7aopab3mi8p5o
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

jkmassel added a commit that referenced this pull request May 25, 2026
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.
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.

3 participants