agentsclimarketplace

Oauth mobile

Skill almasumdev/awesome-mobile-security-agent-skills/.github/skills/auth/oauth-mobile

Agent skills for securing mobile apps: storage, transport, auth, obfuscation, and hardening.

Install
npx -y skills add almasumdev/awesome-mobile-security-agent-skills --skill oauth-mobile

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

OAuth 2.1 + PKCE for native mobile apps. Covers redirect URIs, AppAuth libraries, and the flows that are safe vs deprecated. Use when implementing or reviewing user login.

SKILL.md

4.5 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

OAuth 2.1 on Mobile (with PKCE)

Instructions

Mobile OAuth is a minefield. Use audited libraries, follow RFC 8252 (OAuth 2.0 for Native Apps), and never hand-roll the flow.

1. Allowed Flows

  • Authorization Code + PKCE — the only acceptable interactive flow for native apps (RFC 7636).
  • Device Authorization Grant — acceptable for input-constrained devices (TVs, some wearables).
  • Client Credentials — only for server-to-server. Never ship a client secret in a mobile binary.

Banned on mobile:

  • Implicit flow (returns access tokens in the URL fragment — can leak).
  • Resource Owner Password Credentials ("password grant") — the app sees the user's password.
  • Any flow that relies on a confidential client_secret baked into the app.

2. PKCE — What the Client Does

// code_verifier: 43–128 chars of [A-Z a-z 0-9 -._~]
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = base64url(await sha256(verifier));

// 1. Open system browser (NOT WebView) to /authorize with:
//    response_type=code
//    code_challenge=<challenge>
//    code_challenge_method=S256
//    redirect_uri=<registered>
//    state=<CSRF token>

// 2. On redirect back, exchange code at /token with code_verifier=<verifier>.

code_challenge_method=plain is forbidden. Always S256.

3. Use AppAuth, Not a WebView

PlatformLibrary
Androidnet.openid:appauth
iOSAppAuth-iOS (via SPM / CocoaPods)
Flutterflutter_appauth
React Nativereact-native-app-auth

Why not WebView:

  • Shared cookies enable SSO (Chrome Custom Tabs / ASWebAuthenticationSession).
  • WebViews can be MITMed by a malicious in-app JS bridge.
  • Apple and Google reject apps that collect third-party credentials in a WebView.

4. Redirect URIs

Three acceptable schemes, in order of preference:

  1. App Links (Android) / Universal Links (iOS) — claimed HTTPS URLs, verified by the OS. Best.
  2. Loopback redirect (http://127.0.0.1:<random>) — great for desktop-style flows, limited on mobile.
  3. Private-use URI scheme (com.example.app:/oauth) — acceptable if unique and reverse-DNS. Another app can register the same scheme on Android, so this is a last resort.

Never use http://localhost on iOS (it conflicts with Universal Links) or a scheme you don't own.

5. Android Example (AppAuth)

val serviceConfig = AuthorizationServiceConfiguration(
    Uri.parse("https://id.example.com/authorize"),
    Uri.parse("https://id.example.com/token"),
)

val authRequest = AuthorizationRequest.Builder(
    serviceConfig,
    clientId,
    ResponseTypeValues.CODE,
    Uri.parse("com.example.app:/oauth"),
).setScope("openid profile offline_access")
 .build() // PKCE is generated automatically

val service = AuthorizationService(context)
val intent = service.getAuthorizationRequestIntent(authRequest)
startActivityForResult(intent, RC_AUTH)

6. iOS Example (AppAuth)

let config = OIDServiceConfiguration(
    authorizationEndpoint: URL(string: "https://id.example.com/authorize")!,
    tokenEndpoint:         URL(string: "https://id.example.com/token")!
)
let request = OIDAuthorizationRequest(
    configuration: config,
    clientId:      clientId,
    scopes:        ["openid", "profile", "offline_access"],
    redirectURL:   URL(string: "com.example.app:/oauth")!,
    responseType:  OIDResponseTypeCode,
    additionalParameters: nil
)

currentAuthFlow = OIDAuthState.authState(byPresenting: request, presenting: vc) {
    authState, error in /* persist authState */
}

7. Post-Login Hygiene

  • Validate id_token signature and aud, iss, exp, nonce.
  • Persist the refresh token in Keystore / Keychain (see token-storage).
  • Support end_session_endpoint on logout to revoke the server session, not just drop local tokens.

Checklist

  • Flow is Authorization Code + PKCE with S256.
  • No client_secret is embedded in the app.
  • Authorization is opened in Chrome Custom Tabs / ASWebAuthenticationSession, not a WebView.
  • Redirect URI is an App Link / Universal Link where possible.
  • state and nonce are validated on return.
  • Refresh tokens are stored in Keystore / Keychain.
  • Logout calls the server's end_session_endpoint.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.