Skip to Content
Framework GuidesOAuth on Mobile

OAuth on Mobile

Web apps receive OAuth tokens in a URL fragment on their callback page. A mobile app has no callback page: the system browser must hand control back to the app, and tokens must never travel through the operating system’s URL handler. Ghayma supports two ways to come back and one way to skip the browser entirely.

Custom schemeVerified linkNative sign-in
Setupnonehost association files on your domain + app entitlementsprovider SDK + client IDs
What comes backone-time codeone-time codenothing to redirect (provider ID token)
ProvidersGoogle, GitHubGoogle, GitHubGoogle

A project that only serves a mobile app needs no site: answer No site — only databases, storage and auth at ghayma init and it holds your auth app, databases and buckets without deploying anything.

1. Register where the browser comes back

In the console, open Project → Auth → your app → Allowed Origins and add your app’s deep-link origin exactly:

  • Custom scheme: com.example.app://callback (scheme + host, no path). * never covers a custom scheme, and the link must have a host segment: myapp://callback, not myapp:///callback.
  • Verified link (iOS universal link / Android App Link): the https origin, for example https://app.example.com. Your domain must host the Apple and Google association files.

file, javascript, data, blob, about, vbscript and ftp are refused.

2. Browser flow with a one-time code (PKCE)

  1. Generate a random code_verifier (43–128 characters from A-Z a-z 0-9 - . _ ~) and its challenge BASE64URL(SHA-256(code_verifier)) without padding.
  2. Open this URL in the system browser (ASWebAuthenticationSession on iOS, Custom Tabs on Android, flutter_web_auth_2 in Flutter):
https://auth.ghayma.tech/v1/{appSlug}/auth/google ?redirect_uri=com.example.app://callback &code_challenge=<challenge> &code_challenge_method=S256

Use /auth/github for GitHub. 3. After the provider, the browser is sent to com.example.app://callback?code=<code>. On failure it is sent to com.example.app://callback?error=<message>. 4. Exchange the code within 120 seconds; it works once:

curl -X POST https://auth.ghayma.tech/v1/{appSlug}/oauth/exchange \ -H "Content-Type: application/json" \ -d '{"code":"<code>","code_verifier":"<code_verifier>"}'

Response: the same session body as login.

{ "access_token": "…", "refresh_token": "…", "expires_in": 900, "token_type": "Bearer", "user": { "…": "…" } }

Errors: 400 {"error":"invalid or expired code","code":"invalid_grant"} (unknown, expired, reused, wrong verifier or wrong app), 403 {"error":"Account is disabled"}, 429 with Retry-After.

Web apps keep the fragment flow: without code_challenge the callback still returns #access_token=…. Nothing changes for existing sites.

3. Native sign-in with Google (no browser)

  1. In Google Cloud, create iOS and Android OAuth client IDs in the same project as your web client ID.
  2. Paste them in the console under Google OAuth → Native client IDs (iOS / Android).
  3. Sign in with the Google Sign-In SDK on the device and post the ID token:
curl -X POST https://auth.ghayma.tech/v1/{appSlug}/oauth/id-token \ -H "Content-Type: application/json" \ -d '{"provider":"google","id_token":"<id_token>","nonce":"<nonce if you set one>"}'

Ghayma verifies the token against Google’s public keys, checks that its audience is one of your registered client IDs, creates or links the user by email, and returns the session body. Errors: 401 {"error":"invalid id token","code":"invalid_token"}, 400 when the provider is disabled or the token carries no email, 403 when the app’s user limit is reached or the account is disabled, 429.

Android’s Credential Manager returns tokens whose audience is your web client ID; iOS returns the iOS client ID. Both are accepted once listed.

Rate limits

EndpointPer clientPer app
POST /oauth/exchange20 / 15 min600 / 15 min
POST /oauth/id-token10 / 15 min600 / 15 min

What is coming

  • Sign in with Apple (required by the App Store for iOS apps that offer Google sign-in) is planned.
  • SDKs: the Dart / Flutter SDK (ghayma_auth) is out — it runs the PKCE flow, the code exchange and native Google sign-in for you — and @ghayma/sdk 1.2 ships the PKCE helpers and native sign-in for JavaScript. Swift, Kotlin and PHP are planned.

See the full contract in the Auth Service API.