⚠️ Replace CLIENT_ID and REDIRECT_URI below with your own Services ID and a verified HTTPS domain before this will work — see the README.

Raw response from Apple:

Decoded ID token payload:

How this differs from Google's button flow

Apple's ID token has no name or picture claim — only sub (an opaque per-app user id) and email. The user's name, if you requested the name scope, arrives separately as a JSON string in the response's top-level user field — only the first time that user authorizes your app. Store it then, because Apple won't send it again.

There's also no tokeninfo-style endpoint to call. Apple publishes its public signing keys as a JWKS at https://appleid.apple.com/auth/keys, and expects you to verify the RS256 signature yourself — normally with a JWT/JWKS library on your backend. The "Verify" button here does that check for real, in the browser, with Web Crypto, purely to make it visible (it may hit a CORS error, in which case that's exactly why this belongs on a server instead).

End-to-end flow (all client-side, nothing shown here touches a server):

  1. Browser loads Apple's appleid.auth.js
  2. User clicks the button, Apple's popup opens
  3. User authenticates, Apple signs a JWT and resolves the signIn() promise with it, right in this page's JS
  4. In a real integration you'd hand that raw id_token off to whatever system needs to identify the user — it can verify the signature itself (JWKS lookup) and, only if it also needs Apple's own access/refresh tokens, exchange the code at Apple's token endpoint (requires a JWT client secret signed with your Apple Developer private key)