Add or review authentication in a mobile app or game — manual sign-up (email/password, OTP, magic link) and SSO (Sign in with Apple, Sign in with Google via Credential Manager, Facebook, passkeys), plus Play Games Services v2 and Game Center as game identity, guest-to-account upgrade with save migration, token storage in Keychain/Keystore, session and refresh-token handling, account linking, and the mandatory in-app account deletion both stores require. Use when building login, adding a socia...
Installs into .claude/skills of the current project.
Are you the author of App Auth?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/thomaslimited-app-auth)
---
name: app-auth
description: Add or review authentication in a mobile app or game — manual sign-up (email/password, OTP, magic link) and SSO (Sign in with Apple, Sign in with Google via Credential Manager, Facebook, passkeys), plus Play Games Services v2 and Game Center as game identity, guest-to-account upgrade with save migration, token storage in Keychain/Keystore, session and refresh-token handling, account linking, and the mandatory in-app account deletion both stores require. Use when building login, adding a social provider, migrating from a deprecated sign-in API, linking accounts, or fixing an auth-related store rejection.
license: MIT
metadata:
version: "1.0.0"
specs-verified: "2026-09-24"
---
# App Auth
## Decide first: does this app need accounts at all?
Accounts are a permanent liability: a breach surface, a GDPR data subject, a support queue, a
store-mandated deletion flow, and a place for players to lose progress. Add them only for a reason
you can name.
| Need | Lightest solution that works |
|---|---|
| Save progress on one device | No account. Local save. |
| Restore purchases on a new device | **No account** — the store account already does this. Play and Apple restore entitlements for free. |
| Cloud save across the user's own devices | Platform save: Play Games Services Saved Games, or iCloud/Game Center. Still no account of yours. |
| Leaderboards, achievements | Play Games Services + Game Center. Still no account of yours. |
| Cross-platform progress (iOS ↔ Android ↔ web) | Now you need an account system. |
| Social features, user-generated content, server-authoritative economy | Account system, and a moderation plan. |
**For a children's app, the answer is almost always no accounts.** Collecting a child's email
triggers COPPA/GDPR-K verifiable parental consent, which is far more work than the feature is
worth. See `references/compliance-and-account-deletion.md`.
## If you do need accounts
Pick the smallest set of methods. Every method is a code path, a recovery story and a support
category. A good default for a game with cross-platform progress:
1. **Sign in with Google** (Credential Manager) — covers most Android users in one tap
2. **Sign in with Apple** — required on iOS if you offer any other third-party sign-in (4.8)
3. **Guest** — play first, upgrade later; this is what actually protects your D1 retention
Email/password only earns its place if you need it. If you add it, add passkeys too rather than
password recovery theatre: `references/manual-auth.md`.
## The two rules the stores enforce
- **Apple 4.8 — Login Services.** If your app uses any third-party or social login service
(Google, Facebook, etc.), you must *also* offer an equivalent option that limits data collection
to name and email, lets the user keep the email private, and does not track them. Sign in with
Apple satisfies this. Omit it and you get rejected — reliably.
- **Account deletion (Apple 5.1.1(v), and Google Play's equivalent).** If the app supports account
creation, it must support account **deletion initiated inside the app**. A link to "email
support" is not compliant. Google additionally requires a **web URL** where deletion can be
requested without installing the app, declared in Play Console Data safety.
Both are routine rejection causes. Build them in from the start; retrofitting deletion across a
schema you did not design for it is painful. Details and a compliant deletion design:
`references/compliance-and-account-deletion.md`
## Platform APIs — what is current
| Platform | Use | Do not use |
|---|---|---|
| Android sign-in | **Credential Manager** (`androidx.credentials`) with Google ID + passkeys + passwords | `com.google.android.gms.auth.api.signin` (legacy Google Sign-In) — deprecated since Apr 2024 and removed from the Play Services Auth SDK |
| Android games | **Play Games Services v2** | PGS v1 — deprecated after Sep 2025; the deprecated APIs are removed from the SDK from **15 Jun 2026** |
| iOS sign-in | `AuthenticationServices` — `ASAuthorizationAppleIDProvider`, passkeys via `ASAuthorizationPlatformPublicKeyCredentialProvider` | anything storing a password you rolled yourself |
| iOS games | Game Center (`GKLocalPlayer`) | — |
Play Games Services v2 **decouples platform identity from in-game identity**: it signs the player
in to Google Play Games, but your own account system is separate and yours to manage. If you need
a durable cross-platform user id, you still need Sign in with Google or your own backend.
Provider-by-provider setup: `references/sso-providers.md`
## Guest first, upgrade later
The highest-impact auth decision in a game is letting people play before signing in. The hard
part is not the login — it is **merging** the guest's local progress into the account they sign in
to, especially when that account already has progress from another device.
Never silently overwrite. Present a choice, keep a backup of the discarded side, and make the
merge idempotent. Design and conflict rules: `references/game-identity-and-guest-accounts.md`
## Token handling — non-negotiables
- **Never store tokens in plain preferences.** iOS: Keychain, with
`kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` for refresh tokens. Android: Keystore-backed
encryption, or `EncryptedSharedPreferences`.
- **Short-lived access token, long-lived rotating refresh token.** Rotate on every refresh and
invalidate the family on reuse — reuse detection is what turns a stolen token into one failed
request instead of a permanent session.
- **Never put a client secret in the app.** Mobile apps are public clients. OAuth flows use
**PKCE**, not a secret.
- **Verify ID tokens on your server** — signature, issuer, audience, expiry, and nonce. An ID
token forwarded from the client is a claim, not proof, until you check it.
- Sign out must clear tokens, cached user data **and** the local save's association with that
user, or the next person to sign in on that device inherits state.
## Review checklist
- [ ] Sign in with Apple present if any other social login exists (iOS)
- [ ] In-app account deletion, plus a web deletion URL declared for Play
- [ ] Tokens in Keychain/Keystore, never in plain storage or logs
- [ ] PKCE, no client secret in the binary
- [ ] ID tokens verified server-side
- [ ] Guest→account merge never silently destroys progress
- [ ] A failed sign-in leaves the user able to keep playing (or a clear reason why not)
- [ ] Privacy policy and data-safety declarations list every identity provider used
- [ ] No child's email or personal data collected without verifiable parental consent
## Sources
Verified 2026-09-24:
- [App Review Guidelines 4.8 and 5.1.1(v)](https://developer.apple.com/app-store/review/guidelines/)
- [Credential Manager migration](https://developer.android.com/identity/sign-in/legacy-gsi-migration)
- [Play Games Services deprecation schedule](https://developer.android.com/games/pgs/deprecation)