Authentication
Account Linking

Account Linking

People rarely sign in the same way every time. The same customer might use a phone number on your mobile app and an email on your website. By default those are two separate MojoAuth accounts β€” two profiles, two carts, two subscriptions.

Account Linking joins them into one. After linking, the user can sign in with any of their identifiers (email, phone, …) and always land on the same account.

Every link is confirmed with a one-time passcode (OTP) sent to the identifier being added β€” so a user can only link a phone or email they actually control.


Why you'd use it β€” real-world scenarios

πŸ›’ The returning shopper

Riya bought a jacket last year using her phone number on your app. Today she visits your website and signs in with her email β€” and sees an empty cart and none of her orders, because that's a brand-new account.

With Account Linking, when Riya adds her email to her existing account, both sign-ins now open the same profile, cart, and order history.

πŸ’³ The accidental duplicate (with a subscription)

Aarav subscribed to your Pro plan using his email. Months later he signed up again with his phone without realizing it, and now his phone login shows the Free plan.

He signs into his email account (the one with Pro) and links his phone. The two accounts merge into one β€” Pro intact β€” and from now on either login lands on his paid account.

🏒 Consolidating enterprise users

An employee has one account from SSO and another from a phone sign-in. Linking merges them so their access, roles, and data live in a single identity.

πŸ“ž Support & recovery

A customer lost access to their email but still has their phone. Because both are linked to one account, they can sign in with the phone and keep everything.


How linking works

The user links from the account they're currently signed into β€” that account stays the primary (the "main" account). MojoAuth then chooses one of two behaviors automatically:

BehaviorWhen it happensResult
AttachThe identifier being added has never been usedIt's simply added onto the current account. Still one account.
MergeThe identifier already has its own accountThe two accounts are joined β€” current account is primary, the other becomes secondary. Both are kept and act as one.

The user never picks "attach" vs "merge" β€” it's decided by whether the identifier already exists.

⚠️

Merging accounts that have a subscription or data? Always link from the account you want to keep as the main one. If a user has a paid plan on their email account and a separate phone account, have them sign in with the email and add the phone β€” the email account stays primary and keeps the subscription. Doing it the other way makes the phone the primary, and the app would look for the subscription on the wrong account.


What the user experiences

The user is signed in

They're logged into their account (say, with their email) and open "Add phone number" in your app's account settings.

They enter the other identifier

They type the phone number they want to add.

They receive a one-time code

MojoAuth texts a 6-digit code to that phone (or emails it, for an email).

They enter the code

You verify it with MojoAuth. The accounts are now linked.

Done β€” one account, many sign-ins

From now on the user can sign in with either their email or their phone and reach the same account.


Before you start

Account Linking runs on behalf of a signed-in user, so every call needs both the user's access token and your project API key.

HeaderValue
AuthorizationBearer USER_ACCESS_TOKEN β€” the signed-in user's token
X-API-KeyYour project API key
Content-Typeapplication/json

Base URL: https://api.mojoauth.com

BASE="https://api.mojoauth.com"
AUTH=(
  -H "Authorization: Bearer USER_ACCESS_TOKEN"
  -H "X-API-Key: YOUR_PROJECT_API_KEY"
  -H "Content-Type: application/json"
)

Link an account β€” step by step

Linking is a two-step flow: request a code, then verify it.

Step 1 β€” Request a code

Call /users/link/request with the identifier the user wants to add (an email or a phone). MojoAuth sends an OTP to it and returns a state_id.

curl -s -X POST "$BASE/users/link/request" "${AUTH[@]}" \
  -d '{"phone":"+15550000001"}'

Response

{ "state_id": "66b0a1c2d3e4f5a6b7c8d9e0" }

Step 2 β€” Verify the code

Send the state_id and the code the user received to /users/link/verify.

curl -s -X POST "$BASE/users/link/verify" "${AUTH[@]}" \
  -d '{"state_id":"66b0a1c2d3e4f5a6b7c8d9e0","otp":"123456"}'

Response

{ "message": "Account linked successfully" }

MojoAuth decides attach vs merge for you at this step β€” you don't need to check whether the identifier already had an account.


Unlink an account

There are two independent actions, depending on what you want to undo.

Remove one added identifier β€” POST /users/link/remove. Takes the phone or email to remove from the signed-in account.

curl -s -X POST "$BASE/users/link/remove" "${AUTH[@]}" \
  -d '{"phone":"+15550000001"}'
{ "message": "Account unlinked successfully" }

Signing in after linking

Once linked, signing in with any linked identifier always lands the user on their primary account β€” a duplicate is never created again.

  • Riya signs in with her email β†’ her account.
  • Riya signs in with her linked phone β†’ the same account.
  • The access token, ID token, and /oauth/userinfo all describe the primary account (its ID is the token's sub).

The linked phone number won't automatically appear as a phone_number claim in the token unless the primary account itself has that phone on file β€” the token identifies the account, not every linked contact. Fetch the full profile server-side if you need the complete list of a user's identifiers.


Rules to know

  • Any combination works β€” email + phone, phone + phone, email + email. There's no requirement that the two be different types.
  • A user can add multiple identifiers β€” there's no built-in limit on how many phones or emails an account can have.
  • The current account is always the primary β€” plan your "link from" account accordingly (see the subscription note above).
  • Ownership is always proven β€” every link needs the OTP delivered to the identifier being added.

When linking is blocked

MojoAuth prevents linking that would be unsafe or ambiguous:

If the user tries to…They getWhy
Link their own identifierCannotLinkSelfIt's already their account.
Link while already mergedAlreadyLinkedA merged account can't start another merge.
Link an identifier already merged elsewhereTargetAlreadyLinkedIt belongs to another merged account.
Link an identifier already added to someone elseTargetSecondaryIdentityIt's attached to a different account.
Send no email or phoneIdentifierRequiredNothing to link.
Enter a wrong/expired codeOTPInvalidThe code didn't match.

API summary

ActionMethod & pathBody
Start a link (send OTP)POST /users/link/request{"email":"…"} or {"phone":"…"}
Verify & complete the linkPOST /users/link/verify{"state_id":"…","otp":"…"}
Remove one added identifierPOST /users/link/remove{"email":"…"} or {"phone":"…"}
Undo a mergePOST /users/link/unmerge{}

All four require the Authorization: Bearer … + X-API-Key headers. Full error list in Error Codes.


Frequently asked questions

Does linking merge the two accounts' data (orders, subscriptions)? Linking joins the identities so both sign-ins reach one account. Data lives on whichever account is primary β€” which is why you link from the account that already holds the subscription/data. Combining data from a secondary account (e.g. moving old orders over) is something your application handles.

Can a user undo a link? Yes β€” remove a single added identifier with /users/link/remove, or fully separate merged accounts with /users/link/unmerge.

Which account do tokens represent after linking? Always the primary. No matter which identifier the user signs in with, the access token, ID token, and userinfo describe the primary account.

Do I need to detect whether the identifier already exists before linking? No. Call /users/link/request; MojoAuth automatically attaches or merges as appropriate.