Which browser the app uses
OAuth on Android runs through one of three surfaces, and the choice determines what you can observe.
- A Custom Tab or the system browser runs in a separate process. You see the redirect only through the intent that returns to the app.
- An embedded WebView runs inside the app process. The redirect arrives at a WebViewClient callback, and you can read the page and the navigation history.
- A provider SDK wraps one of those two and hides the URLs behind its own classes, which you unwrap by reading the SDK configuration and its manifest entries.
Read the manifest first. The activity that declares the custom scheme or the App Link host is the activity that receives the authorization code, and that is your observation point.
Capture the redirect
The authorization code arrives as a query parameter on a redirect to the app's registered URI. Three ways to see it, in increasing order of intrusiveness.
- Read the handler that processes the incoming intent and log the URI where it arrives.
- Trigger the flow and watch the log output of the redirect handler.
- Register a competing handler for the same scheme, or drive the browser yourself and pass the resulting URI to the app.
Capture the whole URI rather than the code alone. It usually carries a state value that the app compares against the one it sent, and dropping that comparison in your own client should be a deliberate decision.
Understand PKCE before reproducing it
Most current apps send a code challenge on the authorization request and a code verifier on the token exchange. The verifier is a random string generated in the app. The app hashes it, and the hash travels in the first request. The server stores the challenge and checks it when the code is redeemed.
A captured authorization code is useless without the verifier that produced its challenge. If the app already exchanged the code, the code is consumed as well. To reproduce the flow you generate your own verifier and challenge pair, which means your client makes the authorization request itself instead of replaying the app's.
Detecting PKCE takes one look at the authorization URL the app builds. If it carries a code challenge and a challenge method, the app uses PKCE and the verifier lives in memory only for the seconds between building that URL and redeeming the code. Nothing you capture afterwards will contain it, so plan on running the request yourself from the beginning.
The token exchange and what it leaves behind
The exchange is a form encoded POST to the token endpoint carrying a grant type, the code, the redirect URI and the verifier. It returns an access token, often a refresh token, and an expiry. Some providers also set cookies during the flow, and those cookies can matter more than the token when the API reads them.
Watch the cookie jar across every step. Consent pages, account pickers and the token endpoint may each set cookies that later API calls require. A client that keeps the access token and discards the cookies will authenticate and then fail on the first data request.
Steps you cannot script away
Consent and account selection are browser interactions. You cannot skip them, but you can reduce them to a single pass: run the flow once in a browser you control, capture the redirect, and complete the exchange in code. Where the provider issues a refresh token, that removes the browser from the picture until the grant is revoked.
Refresh tokens rotate on many providers. Store the newest one each time the exchange or refresh returns it, and treat a reused refresh token as an error the server answers by invalidating the grant. Recovering from that means running the browser step again, so a client should never refresh concurrently with itself.
One more detail decides how portable the result is. The redirect URI the app registered is bound to its package name and signing certificate. A client you build cannot reuse that redirect URI, so you either register your own with the provider or complete only the code exchange and keep the browser step on the device.
Related work
Reviewed 28 September 2026 · SReverse research desk