
For longer than I care to admit, “Sign in with Apple” in our consumer app meant a custom OpenID Connect connector I hand-fed client secrets to. Apple rotates those secrets aggressively — they’re signed JWTs with a short life — so roughly every six months a cron job would fumble the renewal and the Apple button would quietly stop working. Support tickets. A rollback. The usual pantomime.
So when Apple showed up as a first-class identity provider in Entra External ID public preview back in February, I flipped it on the same afternoon. GA landed this announcement, and I’ve now run it in production long enough to tell you where it bites.
The setup took ten minutes. The gotcha took a week to surface.
The path is exactly where you’d hope: Entra admin center → External Identities → Identity providers → Add → Apple. And an important scoping note before you get excited — this lives in an external tenant (the External ID / CIAM flavour). It is not for your workforce tenant. If you’re trying to let employees sign in with their personal Apple IDs, wrong tool, close the tab.
You feed it the Apple side: Services ID (your client identifier), Team ID, Key ID, and the private key you generate in the Apple Developer portal. Entra takes over the part I used to hate — it constructs and signs the client-secret JWT and manages the token exchange itself. Apple returns an ID token, Entra validates it and maps the claims into the user object. No more cron job. No more 3 a.m. secret expiry.
The flow your users see is unremarkable, which is the point: an Apple button on the sign-in page, a redirect to Apple, Face ID or password, back to your app. Done.
What Apple actually gives you (spoiler: not much)
Here’s the thing that cost me a week. Apple is deliberately stingy with claims. You get an email — frequently a @privaterelay.appleid.com proxy address if the user chose “Hide My Email” — and, if you asked for it, a name.
The name is the trap. Apple sends the user’s name exactly once, on the very first authorization. Not on subsequent sign-ins. I’d written sign-up logic that read the name claim on every login to keep the profile fresh, tested it against my own repeated logins, and watched it happily blank out display names in production the moment real users came back a second time. Capture name on first sign-up, persist it, and never expect to see it again. Build for minimal, stable claims and you’ll be fine. Assume richness and Apple will teach you humility.
Going from preview to GA: don’t assume your config rode along
GA means production support and the SLAs that come with it — that’s the actual news, and it’s the reason this belongs in a customer-facing app now rather than a pilot.
Before you declare victory, verify the provider is present and configured the way you think it is rather than trusting that the preview object carried over untouched. I checked mine from the Graph side, read-only:
-All handles pagination so you don’t silently miss the provider on a tenant with a long IdP list. And confirm the tenant you’re connected to is the external one — nothing wastes an afternoon faster than querying your workforce tenant and wondering where Apple went.
If I were handing this to the next person: throw away your custom connector, capture the name claim on first sign-up like your database depends on it, and plan for the private-relay email address to be the identifier you actually store. The plumbing is Microsoft’s problem now. Apple’s stinginess is still yours.