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:
| Behavior | When it happens | Result |
|---|---|---|
| Attach | The identifier being added has never been used | It's simply added onto the current account. Still one account. |
| Merge | The identifier already has its own account | The 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.
| Header | Value |
|---|---|
Authorization | Bearer USER_ACCESS_TOKEN β the signed-in user's token |
X-API-Key | Your project API key |
Content-Type | application/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/userinfoall describe the primary account (its ID is the token'ssub).
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 get | Why |
|---|---|---|
| Link their own identifier | CannotLinkSelf | It's already their account. |
| Link while already merged | AlreadyLinked | A merged account can't start another merge. |
| Link an identifier already merged elsewhere | TargetAlreadyLinked | It belongs to another merged account. |
| Link an identifier already added to someone else | TargetSecondaryIdentity | It's attached to a different account. |
| Send no email or phone | IdentifierRequired | Nothing to link. |
| Enter a wrong/expired code | OTPInvalid | The code didn't match. |
API summary
| Action | Method & path | Body |
|---|---|---|
| Start a link (send OTP) | POST /users/link/request | {"email":"β¦"} or {"phone":"β¦"} |
| Verify & complete the link | POST /users/link/verify | {"state_id":"β¦","otp":"β¦"} |
| Remove one added identifier | POST /users/link/remove | {"email":"β¦"} or {"phone":"β¦"} |
| Undo a merge | POST /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.