Kembo
BlogDocsSign in
Kembo

Mobile auth in minutes. Google and Apple sign-in for Expo, Flutter, Capacitor, and Web.

Product

  • Documentation
  • Blog
  • Pricing
  • Get started

Legal

  • Privacy Policy
  • Terms of Service
  • DPA
  • Data Deletion

© 2026 Kembo

Operated by ByteStronauts

← All posts
July 4, 2026·9 min read

Sign in with Apple, the right way: every gotcha for Expo, Flutter, and Capacitor

Sign in with Apple is mandatory the moment you offer Google login — and it is the auth that quietly breaks during App Review. Here is every gotcha that bites mobile teams, from the relay email to the name you only get once, and how to get it right on Expo, Flutter, and Capacitor.

Sign in with AppleiOSExpoFlutterOAuthmobile auth

Sign in with Apple is the auth method most teams add last and understand least. It is also the one that gets your build rejected. The moment your app offers a third-party login like Google or Facebook, Apple's guidelines require you to offer Sign in with Apple too — and reviewers check. So the feature you bolted on at the end becomes a gate on your entire release.

The good news: Sign in with Apple is not hard once you know where the landmines are. The bad news: almost every landmine is invisible until you hit it on a real device, the week you are trying to ship. This post walks through every gotcha that bites mobile teams and how to handle it cleanly on Expo, Flutter, and Capacitor.

Why it is mandatory (and when)

App Store Review Guideline 4.8 is the rule that catches people. In plain terms: if your app uses a third-party or social login service to set up or authenticate an account, you must also offer an equivalent login that limits data collection to the user's name and email and lets them hide their email. Sign in with Apple is the obvious way to satisfy that.

  • Offer only email/password? You do not strictly need it (though many add it anyway).
  • Offer Google, Facebook, or similar? You almost certainly must offer Sign in with Apple on iOS.
  • It must be offered with equivalent prominence — you cannot bury it three taps below the Google button.

Gotcha 1: You get the user's name exactly once

This is the single most common bug. Apple returns the user's full name and email only on the very first authorization. On every subsequent sign-in, those fields come back empty — you get a stable user identifier and nothing else. Teams that read name and email straight into the session on each login end up with a database full of users named "null."

The fix is a habit, not a library: capture the name and email on the first response and persist them server-side immediately. Treat the first authorization as your only chance.

Test the second sign-in, not just the first

Your demo always works because you are testing the first authorization. Delete the app, revoke access in Settings → your Apple ID → Sign in with Apple, and sign in again to see what a returning user actually sends. If your account creation depends on name/email being present every time, this is where it breaks.

Gotcha 2: The private relay email

Users can choose "Hide My Email," and Apple hands you a random @privaterelay.appleid.com address that forwards to their real inbox. That is by design and you must support it. Two consequences most teams miss:

  • To send mail to that relay address, your sending domains must be registered and verified with Apple, or your emails bounce.
  • The same person signing in with Google (real email) and Apple (relay email) looks like two accounts unless you deliberately link them. Pick a strategy — usually link on the verified Apple user identifier — and apply it consistently.

Gotcha 3: Native flow on iOS, web flow everywhere else

Sign in with Apple has two shapes. On a real iPhone you want the native system sheet (Face ID, no browser). On Android, the web, and the simulator you fall back to a web OAuth flow that uses a Services ID and a redirect URI. They are configured differently in the Apple Developer portal, and mixing them up produces the dreaded invalid_client error.

  • App ID with the Sign in with Apple capability → powers the native iOS flow.
  • Services ID + a verified domain + a return URL → powers the web flow used on Android, web, and your backend token exchange.
  • A private key (the .p8 file) → used server-side to generate the client secret. Download it once; Apple will not let you re-download it.

Per-platform notes

Expo. Use the native module on iOS for the system sheet, and a web-based flow on Android and web. Sign in with Apple needs a real development build or a production build — it does not work in a plain Expo Go session — so budget time to build to a device before you trust your testing.

Flutter. The community sign_in_with_apple package handles the native sheet on iOS and the web flow elsewhere, but you still own the Services ID, return URL, and the server-side token verification. The package gets you the credential; validating it and minting your own session is on you.

Capacitor. A native plugin gives you the system sheet on iOS; on the web you run the JS-based flow. As with the others, the redirect URI and verified domain have to match exactly or the web path fails.

The rejections that actually happen

  1. Sign in with Apple missing while Google is present — straightforward 4.8 rejection.
  2. Buried or smaller button — reviewers expect roughly equal prominence.
  3. Broken returning-user flow — the app crashes or creates a blank account because name/email came back empty.
  4. No way to delete the account — unrelated to Apple login specifically, but it travels with auth and trips up the same builds. We cover that in a later post.

How Kembo handles Sign in with Apple

Every gotcha above is undifferentiated work — the same setup for every app, with no product value once it works. Kembo exists so you do not have to relearn it per project. We host the full Sign in with Apple flow: the native sheet on iOS, the web fallback elsewhere, the Services ID and key plumbing, the server-side credential verification, and the relay-email edge cases.

  • We persist the name and email on first authorization so your returning users are never blank.
  • We give you one stable user per person and a hook to read the signed-in user in your screens — no token juggling.
  • The same drop-in AuthView renders Apple and Google side by side with equal prominence, so you pass 4.8 without rearranging your UI.

Add it before review week, not during

The reason Sign in with Apple feels painful is timing: teams add it the day they submit, then burn the week fixing the relay email and the empty-name bug. Wire up your sign-in screen with both providers early, test the returning-user path on a real device, and review week becomes boring.

Ship it once, forget about it

Sign in with Apple is not the place to express your product's personality. It is a compliance and trust requirement that should work identically in every app you ship. Get the first-authorization capture right, support the relay email, use the native sheet on iOS with a web fallback elsewhere, and present it with equal prominence — and it stops being a launch risk.

Or skip the relearning entirely. Create a free Kembo project, drop in AuthView, and get Apple and Google sign-in that already handles the edge cases — so the only thing left for review week is shipping. Next week we go deep on the other half of the pair: Google sign-in, OAuth clients, and SHA fingerprints.

Ready to skip the Wednesday OAuth panic? Create a free Kembo project.