Social LiveDocumentationPLATFORM DOCS

Social Login (Apple & Google)

Sign in with Apple or Google -verified on the backend, issuing the same session as an OTP login.

Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

TL;DR -"Sign in with Apple" and "Sign in with Google" are a third way to prove who you are. The phone gets an ID token from Apple or Google, the backend checks it's genuine, and then issues the exact same session tokens as a one-time-code login. It reuses one account per person -social and email sign-in reach the same account.

Who this is for -Product & business: the intro and "Account resolution" explain the user experience and the Apple App Store rule. Backend, security & mobile: token verification against provider JWKS, the resolution order, and the one-time provider/native setup.

Some people would rather tap "Sign in with Apple" or "Sign in with Google" than wait for a texted code. Social login gives them that option. The idea: your phone asks Apple or Google to vouch for you, they hand back a signed "ID token" (a tamper-proof digital note saying "yes, this is really them"), and our backend checks that note is authentic before letting you in.

Crucially, this does not create a second, parallel login system. Once the note checks out, you get the same session -the same access and refresh tokens -as anyone who logged in with a one-time code. And if you've used both an email code and Google (with the same verified email), they land on the same account, not two.

Social login is a third way to obtain a verified identity -it does not introduce a second session system. The device gets an ID token from Apple or Google, the backend verifies it, resolves or creates the user, and issues the same access/refresh JWT session that OTP login does.

In plain terms

  • Tap-to-sign-in. No code to wait for; the phone gets a signed note from Apple or Google.
  • We verify it ourselves. The backend checks the note's signature against Apple's/Google's public keys -nothing is trusted just because the phone said so, and no shared secret or web callback is involved.
  • One account per person. If your Google email matches an account you already verified by email code, they're linked -you don't end up with duplicates.
  • Apple is required alongside Google on iOS. Apple's rules say if you offer any social login on iOS, you must also offer Sign in with Apple.

Endpoint

The phone sends the provider's ID token to one endpoint:

POST /auth/social

{
  "provider": "apple" | "google",
  "idToken": "<provider ID token (JWT)>",
  "firstName": "…",      // optional; Apple only sends the name on first auth
  "lastName":  "…",      // optional
  "displayName": "…",    // optional
  "ageConfirmed": true,  // required when this creates a new account (18+ gate)
  "platform": "ios" | "android" | "web",  // + optional device fields
  "installationId": "…"
}

Returns the standard AuthSession (userId, accessToken, refreshToken, expiresAt).

Token verification

This is the "we verify it ourselves" step, in detail -the check happens locally against each provider's public keys. social-token-verifier.ts verifies the ID token against each provider's published JWKS -signature, issuer, audience, and expiry are all checked locally. No provider secret or callback is involved.

  • Apple -issuer https://appleid.apple.com, JWKS …/auth/keys, audience must be in APPLE_SIGNIN_CLIENT_IDS (the app's bundle id, plus a Service ID for web if used).
  • Google -issuer accounts.google.com, JWKS …/oauth2/v3/certs, audience must be in GOOGLE_SIGNIN_CLIENT_IDS (every OAuth client id that can mint a token for the app -include the mobile SDK's serverClientId).

Account resolution (in order)

Once the token is verified, the backend decides which account it belongs to, trying these in order -this is what guarantees "one account per person":

  1. Linked identity -a SocialIdentity row already exists for (provider, subject) → log that user in.
  2. Verified-email merge -the token carries a provider-verified email that matches an existing account's verified email → link a new SocialIdentity to it (so email-OTP and social sign-in reach the same account).
  3. New account -enforce the 18+ gate (ageConfirmed), create the user (+ profile + wallet), attach the email only if verified and not already taken, and create the SocialIdentity.

SocialIdentity is @@unique([provider, subject]); subject is the provider's opaque sub claim -never the email.

Provider / native setup (one-time)

Getting social login working requires some one-time configuration in Apple's and Google's developer consoles and in the app project.

Apple -enable the Sign in with Apple capability on the App ID in the Apple Developer portal, and add the capability in Xcode (Runner → Signing & Capabilities → + Sign in with Apple). The sign_in_with_apple package handles the rest on-device.

Google -in Google Cloud Console create OAuth client IDs (iOS + Web). Put the iOS client id and the Web ("server") client id into lib/modules/auth/data/social_auth_service.dart (or the iOS Info.plist GIDClientID + reversed-client-id URL scheme), and list the Web client id in GOOGLE_SIGNIN_CLIENT_IDS. On Android, register the app's SHA-1 fingerprints on the OAuth client.

App Store rule: offering Google (or any social) login on iOS requires Sign in with Apple to be offered too (Guideline 4.8).