Skip to content
OAuth in mobile apps: use PKCE, and stop shipping client secrets in the APK
article3 min read159 viewsSep 11, 2026

OAuth in mobile apps: use PKCE, and stop shipping client secrets in the APK

Fatima Al-Sayed@fatima_appsec

September 11, 2026 · 3 min read

#1 in Security Theatre

159 views3 comments

Every few months I review a mobile app that ships an OAuth client secret inside the binary. Extracting a string from an APK or IPA takes about ten minutes, so that secret is public the day the app is published. Here is the setup that actually works for native apps.

Mobile apps are public clients

A public client is one that cannot keep a secret: native apps, single page apps, desktop apps. The OAuth specs say so explicitly, and the answer is not better obfuscation. The answer is a flow that does not need a secret: authorization code with PKCE.

How PKCE works

  1. The app generates a random code_verifier (43 to 128 characters, from a cryptographically secure generator).
  2. It computes code_challenge = BASE64URL(SHA256(code_verifier)) and sends the challenge with code_challenge_method=S256 in the authorization request.
  3. The user logs in, and the authorization server redirects back to the app with a one-time code.
  4. The app exchanges the code for tokens and sends the original code_verifier. The server hashes it and checks that it matches the challenge.

If another app on the device intercepts the redirect and steals the code, it cannot use it, because it does not have the verifier. That is the whole trick, and it is why the implicit flow is no longer recommended. The OAuth security best current practice tells you not to use implicit at all.

Use the system browser, not a WebView

Open the login page in the system browser component: ASWebAuthenticationSession on iOS, Custom Tabs on Android. Not an embedded WebView. In a WebView your app can read everything the user types, including their password for the identity provider, and the user cannot see a real address bar. Many providers block embedded WebViews for this reason. RFC 8252, OAuth for native apps, covers this in detail.

Store tokens in the platform keystore

Refresh tokens go in the iOS Keychain or in Android Keystore-backed storage. Not in AsyncStorage, not in plain SharedPreferences, not in a SQLite table. Use short-lived access tokens, and if your provider supports refresh token rotation, turn it on.

Checklist

  • Authorization code + PKCE with S256. No implicit flow, no plain method.
  • No client secret in the app. If your provider insists on one, your backend should do that part.
  • System browser for login, never a WebView.
  • Exact redirect URI matching on the server side.
  • Tokens in Keychain or Keystore. Short access token lifetime, rotating refresh tokens.

None of this is new. But I still find the secret in the APK, so apparently it needs repeating.

Written by

Fatima Al-Sayed

Application security engineer at a bank in Dubai. Threat modelling, auth flows, secure code review. I will ask where your JWT secret lives. Arabic coffee enthusiast.

Get the best of #security-theatre weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.

Comments

3

Sign in to join the conversation.

Sign in to comment
Tunde Adebayo@tunde_ade#4 in Security Theatre
we shipped a client secret inside the apk in 2021. a "security researcher" emailed us the secret 2 days after launch, with a bounty request attached. omo. this post is personal
2 net votes
Grace Wanjiru@grace_wanjiru#6 in Security Theatre
Very clear, thank you. Kindly also say something about the redirect URI. Our Android app uses a custom scheme and I read somewhere that another app can register the same scheme.
1 net votes
Fatima Al-Sayed@fatima_appsec#1 in Security Theatre
Correct, custom schemes are not unique, any app can register myapp://. Two things. PKCE already protects you, because the other app does not have the verifier. And where you can, use claimed https links (Android App Links, iOS Universal Links), which are verified against your domain. Custom scheme + PKCE is acceptable, https link + PKCE is better.
5 net votes