← All docs Games for Group · Runbook

Sign in with Apple — switching it on

The app offers Google and Apple sign-in for hosts. The Apple button ships in the code and the backend knows the provider; it works the moment the two values below exist on the Convex deployment. Everything on this page happens in Karim's Apple developer account and on Karim's machine — it involves a private key, so nobody else does it.

In one line: make a Services ID and a key in the Apple developer account, turn the key into a signed client secret with the script in scripts/, and set AUTH_APPLE_ID + AUTH_APPLE_SECRET on Convex. The secret expires every six months — put a reminder in the calendar.
Where it stands. Switched on: all five steps are done, and AUTH_APPLE_ID and AUTH_APPLE_SECRET are both set on the dev and production deployments. The values:
Team IDAL7Y7C2959
Services IDcom.karimdev.gamesforgroup.signin (domains + return URLs registered for dev upbeat-scorpion-654 and prod clean-poodle-980)
Key IDTZXQXFP2MM — keep the .p8 file in a password manager; Apple never lets you download it again
The secret expires 5 March 2027. The renewal steps are in RENEWALS.md at the repo root.

What you will end up with

ValueWhere it comes fromGoes to
Team IDApple developer account → Membershipthe secret script
Services ID (e.g. com.karimdev.gamesforgroup.signin)Identifiers → Services IDsAUTH_APPLE_ID and the script
Key ID + the .p8 fileKeys → the Sign in with Apple keythe script (never Convex, never git)
Client secret (a signed token)the script's outputAUTH_APPLE_SECRET

Step 1 — the App ID has Sign in with Apple

  1. developer.apple.com → Account → Certificates, Identifiers & Profiles → Identifiers.
  2. Open the App ID com.karimdev.gamesforgroup (the app's bundle id from app.json).
  3. Tick Sign In with Apple in the capability list, Save. (If the app already had the capability, nothing to do.)

Step 2 — a Services ID (this is the client id)

  1. Identifiers → the + button → choose Services IDs → Continue.
  2. Description: Games for Group sign-in. Identifier: com.karimdev.gamesforgroup.signin. Continue → Register.
  3. Open the new Services ID, tick Sign In with Apple, click Configure:
    • Primary App ID: com.karimdev.gamesforgroup.
    • Domains and Subdomains: the Convex site domains, one per deployment — the dev one is upbeat-scorpion-654.convex.site; add the production deployment's <name>.convex.site too (it is the "HTTP Actions URL" on the Convex dashboard, without https://).
    • Return URLs: https://<deployment>.convex.site/api/auth/callback/apple, one line per deployment.
    Save, then Continue → Save on the Services ID itself.

Apple only accepts https return URLs on real domains — that is why the callback lives on the Convex site, not on the phone. The app finishes the round-trip on its own scheme afterwards, exactly as it does for Google.

Step 3 — a key

  1. Keys → +. Name: Games for Group Sign in with Apple.
  2. Tick Sign In with Apple → Configure → Primary App ID com.karimdev.gamesforgroup → Save → Continue → Register.
  3. Download the .p8 file. Apple lets you download it once. Keep it somewhere private (a password manager's file vault). Note the Key ID shown on that page.
  4. Note the Team ID from Account → Membership details.

Step 4 — turn the key into the client secret

Apple does not give you a client secret; you sign one yourself with the key. The repo has a script for it (no dependencies, Node only). Run from the repo root:

node scripts/apple-client-secret.mjs \
  --team <TEAM_ID> \
  --key-id <KEY_ID> \
  --client-id com.karimdev.gamesforgroup.signin \
  --key ~/path/to/AuthKey_<KEY_ID>.p8

It prints one long token. That token is AUTH_APPLE_SECRET. It is valid for six months (Apple's maximum) — the script prints the expiry date; rerun it and reset the variable before then.

Step 5 — set the two values on Convex

Once for dev, once for production (add --prod):

bunx convex env set AUTH_APPLE_ID com.karimdev.gamesforgroup.signin
bunx convex env set AUTH_APPLE_SECRET <the token from step 4>

No deploy is needed after this — the provider reads the values on each sign-in.

Step 6 — try it

  1. App → Host a room → Continue with Apple. Apple's sheet appears; on the very first sign-in it offers to hide your email.
  2. Back in the app the room form shows, with your name prefilled from Apple. (Apple sends the name only on the FIRST sign-in ever for that Apple ID — if you test repeatedly, remove the app under Apple ID → Sign-In and Security → Sign in with Apple to see a first-time flow again.)

If it does not work

You seeUsually means
"Sign-in did not complete" toast straight awaythe two env values are missing or the secret expired — bunx convex env list
Apple page: invalid_clientServices ID mismatch — AUTH_APPLE_ID must be the Services ID, not the App ID
Apple page: invalid_request · redirect_urithe Return URL on the Services ID does not match https://<deployment>.convex.site/api/auth/callback/apple exactly
Signed in but no nameexpected after the first sign-in — Apple never sends it again; the host types it once and the app remembers
Apple accepts the password, the app shows "something went sideways"the users insert failed — check bunx convex logs. Seen once for image: null (fixed 7 Sep by mapping the profile by hand); the same shape of failure would come from any new field Apple sends as null

Why Apple at all: App Store guideline 4.8 — an app that offers any third-party sign-in must also offer Sign in with Apple. The rule is enforced at review, so the button shipped with the Google one (see decisions.html, 2026-09-06).

Last updated: 2026-09-14