twobotechnologies

Mobile security · Authorization · 4 min read

Integrating OAuth With Mobile Apps: The Native App Pattern

Short answer

A native app should run the OAuth authorization code flow with PKCE in the system browser (ASWebAuthenticationSession on iOS, Custom Tabs on Android), receive the code on a claimed HTTPS link or private-use URI scheme, and store tokens in the platform keychain or keystore, as RFC 8252 describes.

Key takeaways

  • Native apps are public clients: they cannot keep a client secret, so PKCE is mandatory.
  • Use the system browser, not an embedded webview, so users see the real sign-in page and keep their existing session.
  • Prefer claimed HTTPS redirect URIs (Universal Links, App Links) over custom schemes where you can.

When smartphones took off, teams wired OAuth into apps in every way imaginable: client secrets compiled into binaries, login forms inside webviews, tokens saved to plain files. Most of those shortcuts have since been documented as mistakes. The resulting guidance, RFC 8252 "OAuth 2.0 for Native Apps", is short and worth reading in full.

Why are mobile apps different from web apps?

A mobile app runs on a device you do not control, so it cannot keep secrets, and its redirect URI can potentially be claimed by another app.

A server-side web app keeps its client secret on the server and receives the authorization code at an HTTPS address only it controls. A native app has neither luxury. Anyone can unpack the app and read its configuration. On older platforms, any app could register the same custom URI scheme and intercept the redirect. These facts drive the rest of the design.

The authorization code flow with PKCE, executed in an external user agent (the system browser), with the code returned to the app on a redirect URI it owns.

Step by step:

  1. The app generates a random code_verifier and its S256 code_challenge. Our PKCE Generator shows exactly what these look like.
  2. It opens the authorization URL in the system browser component: ASWebAuthenticationSession on iOS and macOS, Custom Tabs on Android.
  3. The user signs in on the real identity provider page, possibly already logged in from earlier browser use.
  4. The provider redirects to the app's redirect URI with a code and the state.
  5. The app checks state, then posts the code and the code_verifier to the token endpoint.
  6. It receives an access token, usually a refresh token, and an ID token if it requested openid.

PKCE is what makes step 4 safe: even if another app intercepts the code, it cannot redeem it without the verifier, which never left the original app.

Which redirect URI should a native app use?

A claimed HTTPS link is best; a private-use scheme based on a domain you own is acceptable; a loopback address suits desktop apps.

Redirect type Example Notes
Claimed HTTPS https://app.example.com/oauth/callback iOS Universal Links, Android App Links; ownership verified by the OS
Private-use scheme com.example.app:/oauth/callback Use reverse domain notation to avoid collisions
Loopback http://127.0.0.1:51004/callback Desktop apps; the server must allow any port

Generic schemes such as myapp:// invite collisions. Whatever you choose, register it exactly with the authorization server.

How should tokens be stored and used?

Keep tokens in the platform's secure storage, keep access tokens short-lived, and rotate refresh tokens.

On iOS, use the Keychain with an appropriate accessibility class. On Android, encrypt with a key held in the Android Keystore. Do not log tokens. Send them only over TLS. If the API supports it, sender-constrained tokens such as DPoP (RFC 9449) bind a token to a key the app holds, so a copied token is not enough on its own.

Refresh token rotation, where each use returns a new refresh token and invalidates the old one, helps detect theft: if an attacker and the real app both use the same refresh token, the server sees the reuse and can revoke the session.

What about apps for business users and BYOD?

On managed or work-profile devices, the same flow applies, and device management can add conditions such as requiring a compliant device before the token is issued.

Identity providers can check device state through MDM integration and issue tokens only to compliant devices. That belongs to the bigger topic covered in our mobile security guide and the BYOD articles on this site.

What are the most common mistakes?

Webview logins, shipped client secrets, missing PKCE and unchecked state.

Each one has caused real incidents. Check your own app's authorization request with the Authorization URL Builder; it warns when PKCE or state is missing and when a redirect URI looks risky.

Questions

Why not use a webview for login?

An embedded webview lets the app read everything the user types, including the password, and it does not share cookies with the browser, so users must sign in again. RFC 8252 says native apps must not use embedded user agents for authorization requests, and many identity providers block them.

Can I put a client secret in the app?

No. Anything shipped in an app binary can be extracted. Treat the app as a public client and rely on PKCE and redirect URI validation instead.

Where should a mobile app store refresh tokens?

In the iOS Keychain or the Android Keystore-backed storage, never in plain shared preferences or files. Consider refresh token rotation so a stolen token is detected.

Sources

Tagged: OAuth, OAuth 2.0, Mobile, Authorization code flow, Android, Mobile security

The Twobo Technologies editors write practical explainers on identity and API security and maintain the free tools on this site. Spotted an error or an outdated detail? Email contact@twobotechnologies.com.

Related articles