Prompt

Can you help me design a login flow that supports Google, Apple, and Microsoft sign in plus account linking?

Technology / Identity & Access1 observationLast seen Oct 6, 2026

Latest observation

Oct 6, 2026OpenAI APIWeb search: off

Absolutely — here’s a solid, modern login/account-linking design that supports Google, Apple, and Microsoft while avoiding duplicate accounts and making linking safe.


1) Core principle

Use a single internal user account and attach one or more external identities to it.

Data model

users

  • id
  • email (optional but useful)
  • email_verified
  • name
  • created_at
  • updated_at
  • other profile fields

auth_identities

  • id
  • user_id → FK to users.id
  • provider → google | apple | microsoft
  • provider_subject → stable unique ID from provider (sub, oid, etc.)
  • provider_email → email returned by provider
  • provider_email_verified
  • created_at
  • last_login_at

Uniqueness constraints

  • Unique on (provider, provider_subject)
  • Optional unique on email in users if your product requires one account per email

This lets one user link:

  • Google
  • Apple
  • Microsoft
  • potentially email/password later too

2) Recommended sign-in behavior

On successful OAuth/OIDC callback:

  1. Validate provider tokens.
  2. Extract:
    • stable provider user ID
    • email
    • email verification status
  3. Determine whether this login should:
    • create a new user
    • log into an existing linked account
    • prompt account linking

3) Account resolution logic

Use this order:

A. If provider identity already linked

If (provider, provider_subject) exists:

  • log the user into that user_id

B. Else if email matches an existing user

If provider returns a verified email that matches an existing user:

  • do not auto-merge silently
  • show a “We found an existing account” linking flow

Why? Because:

  • Apple may hide relay emails
  • Microsoft/Google emails can differ across work/personal accounts
  • email alone is not always a secure proof of identity

C. Else create a new user

If no existing identity and no safe email match:

  • create new users row
  • create linked auth_identities row
  • log in

4) Safe account linking flow

Linking should happen only when the user is already authenticated in your app.

Linking steps

  1. User signs into app with existing account.
  2. User goes to “Connected accounts”.
  3. Clicks “Link Google / Apple / Microsoft”.
  4. OAuth flow starts.
  5. On callback:
    • validate provider token
    • check if that provider identity is already linked to another user
      • if yes, block and explain
    • otherwise attach identity to current user

Important rule

If the provider identity is already linked to a different user:

  • do not merge automatically
  • require support/manual review or special recovery flow

5) Best practice for “first login” vs “linking”

You need to distinguish the intent:

login flow

Used when user wants to sign in.

link flow

Used when logged-in user wants to add another provider.

Implementation-wise:

  • add a state/nonce value that includes intent
  • store the current app session for linking
  • on callback, process accordingly

6) Suggested sign-in UX

On login page

Buttons:

  • Continue with Google
  • Continue with Apple
  • Continue with Microsoft

After OAuth callback:

If matched by linked identity

  • sign in immediately

If matched by verified email but not linked

Show:

  • “An account already exists with this email”
  • options:
    • Sign in another way
    • Send magic link / email verification
    • If already authenticated, link this provider
    • Contact support if you can’t access the original account

If new user

  • create account automatically
  • optionally ask for profile completion later

7) Handling Apple specifically

Apple is a little special:

  • The real stable identifier is the Apple sub
  • Email may be:
    • real email
    • private relay email
    • missing on later sign-ins
  • Name may only be provided on the first consent

Apple rule of thumb

Never rely on Apple email as the unique identifier. Use Apple sub for identity linking.


8) Handling Microsoft specifically

Microsoft accounts can be:

  • personal Microsoft accounts
  • work/school Entra ID accounts

Recommendation

Decide whether you support:

  • personal accounts only
  • both personal + work/school

Store provider metadata so you can distinguish tenant/account type if needed.


9) Suggested callback decision table

Existing linked identity?Verified email matches user?Action
YesanySign in existing user
NoYesPrompt to link / confirm account ownership
NoNoCreate new user
Yes but linked to another useranyReject + manual resolution

10) Security considerations

Use OIDC, not just OAuth

Prefer OpenID Connect for authentication because you get:

  • ID token
  • verified subject
  • email claims where available

Validate:

  • issuer
  • audience/client_id
  • signature
  • expiration
  • nonce
  • state

Never:

  • trust provider email without checking verification
  • auto-merge accounts solely by matching email
  • link identities without the user being authenticated or explicitly confirming ownership

11) Recovery flows you should plan for

Case 1: User signed up with Google, now tries Apple with same email

  • If not already linked, ask them to sign in to the original account first and then link Apple.

Case 2: User loses access to original provider

  • offer support-assisted recovery
  • or allow verified email recovery if your risk tolerance permits

Case 3: Apple relay email changes

  • identity still works because you key off Apple sub

Case 4: Microsoft email differs from Google email for same person

  • these are separate accounts unless user links them

12) Practical implementation pattern

Pseudocode

onOAuthCallback(provider, idToken, accessToken, intent, currentUser):
    claims = verifyAndDecode(idToken)

    providerSubject = claims.sub
    email = claims.email
    emailVerified = claims.email_verified

    existingIdentity = findIdentity(provider, providerSubject)

    if existingIdentity:
        logIn(existingIdentity.user_id)
        return

    if intent == "link":
        if currentUser is null:
            reject("Must be signed in to link accounts")

        if identityExistsForAnotherUser(provider, providerSubject):
            reject("This provider account is already linked elsewhere")

        createIdentity(user_id=currentUser.id, provider, providerSubject, email, emailVerified)
        return success("Linked")

    existingUser = findUserByVerifiedEmail(email)

    if existingUser:
        showLinkOrRecoverFlow(existingUser)
        return

    user = createUser(email=email, email_verified=emailVerified)
    createIdentity(user.id, provider, providerSubject, email, emailVerified)
    logIn(user.id)

13) Recommendation for your exact product

If you want the safest and simplest approach:

  1. Use OIDC for Google, Apple, Microsoft
  2. Store one internal user table
  3. Store provider identities separately
  4. Login by linked identity
  5. Only link while the user is already authenticated
  6. Do not auto-merge on email alone
  7. Allow email match to trigger a recovery/linking prompt

14) Good default policy

Here’s a sensible policy to start with:

  • Login by provider subject
  • Link only from an authenticated session
  • If email matches but identity not linked, prompt the user
  • If an identity is already linked to another user, block
  • Apple sub is source of truth
  • Require verified emails where available
  • No silent merges

If you want, I can also turn this into:

  1. a sequence diagram,
  2. a database schema, or
  3. backend endpoint design for /auth/callback, /auth/link, and /auth/unlink.

Observation history

How did Obsurfable measure this prompt?

Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.

Which AI systems does Obsurfable collect answers from?

OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, Meta AI, Qwen.

How can brands improve their AEO?

Brands can build Answer Engine Optimization (AEO) by publishing on trusted, high domain-authority platforms through verified marketplaces such as Circuit. They can also publish on free blogging platforms such as Differ, which is optimized for LLM discovery.

Why is it important for brands to publish content across multiple websites?

Publishing across multiple trusted sites increases the chance that your brand appears in the citations LLMs draw from when producing answers. Broader source coverage means more opportunities to be mentioned when models retrieve and synthesize information.

Want this interpreted for your brand?

Explorer is the free public corpus. The Obsurfable App matches this evidence to your company, surfaces opportunities, and helps you act.