Skip to content

Add helper APIs for authentication callback handling #1198

@jkmassel

Description

@jkmassel

Context

While integrating the OAuth2 support from #1190 into GutenbergKit's Android demo app, we found that apps end up with significant boilerplate for handling authentication callbacks. The OAuth flow already has parseTokenResponse for parsing the callback URL, but there's no equivalent for Application Passwords, and the OAuth post-callback token exchange is also manual.

Every app using wordpress-rs needs to implement the same callback handling logic regardless of platform. The platform-specific parts (launching a browser, receiving the deep link) are minimal — the bulk of the work is parsing, token exchange, and Account creation that could live in the Rust layer.

Proposed additions

1. Application Passwords callback parsing

Currently every app manually extracts site_url, user_login, password query parameters from the callback URL and combines them with the apiRootUrl from the discovery result to build an Account.SelfHostedSite. This is the direct equivalent of parseTokenResponse for OAuth.

// Something like:
parseApplicationPasswordsCallback(url, discoverySuccess) -> Account.SelfHostedSite

2. Application Passwords auth URL builder

Every app adds the same app_name, app_id, success_url query parameters to the authentication URL. A builder matching the OAuth pattern (buildTokenRequestUrl) would reduce this:

// Something like:
buildApplicationPasswordsUrl(authMechanism, appName, appId, redirectUri) -> URL

3. OAuth token exchange

After parseTokenResponse, every app still needs to: create a WpComApiClient, call oauth2().requestToken(), extract the token and blog ID, call wordpressComSiteApiRoot(), and assemble the correct Account type. This could be a single call:

// Something like:
completeOAuthTokenExchange(callbackUrl, expectedState, oauthConfig) -> Account

Priority

Items 1 and 2 are the lowest-hanging fruit — pure parsing and URL construction with no async or networking. Item 3 is more involved since it requires an HTTP client but would eliminate the most boilerplate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions