Paid Feature
This is a paid feature. For self hosted users, Sign up to get a license key and follow the instructions sent to you by email. This will start a SuperTokens subscription.
If you are using the development environment of our managed service you can use this feature for free. If you want to enable this feature for the production environment, please email us
Manual account linking
Manual account linking allows you to take control of when and which accounts are linked. With this, you can implement flows like:
- Connecting social login accounts to an existing account post login.
- Adding a password to an account that was created with a social or passwordless login.
- Linking accounts which don't have the same email or phone number, or have a different identifier alltogether.
#
Creating a primary userIn order to link two accounts, you first need to make one of them a primary user:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import AccountLinking from "supertokens-node/recipe/accountlinking";
import {RecipeUserId} from "supertokens-node";
async function makeUserPrimary(recipeUserId: RecipeUserId) {
let response = await AccountLinking.createPrimaryUser(recipeUserId);
if (response.status === "OK") {
if (response.wasAlreadyAPrimaryUser) {
// The input user was already a primary user and accounts can be linked to it.
} else {
// User is now primary and accounts can be linked to it.
}
let modifiedUser = response.user;
console.log(modifiedUser.isPrimaryUser); // will print true
} else if (response.status === "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR") {
// This happens if there already exists another primary user with the same email or phone number
// in at least one of the tenants that this user belongs to.
} else if (response.status === "RECIPE_USER_ID_ALREADY_LINKED_WITH_PRIMARY_USER_ID_ERROR") {
// This happens if this user is already linked to another primary user.
}
}
note
Coming Soon
note
Coming Soon
#
Linking accountsOnce a user has become a primary user, you can link other accounts to this user:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import AccountLinking from "supertokens-node/recipe/accountlinking";
import { RecipeUserId } from "supertokens-node";
// we are linking the input recipeUserId to the primaryUserId
async function linkAccounts(primaryUserId: string, recipeUserId: RecipeUserId) {
let response = await AccountLinking.linkAccounts(recipeUserId, primaryUserId);
if (response.status === "OK") {
if (response.accountsAlreadyLinked) {
// The input users were already linked
} else {
// The two users are now linked
}
let modifiedUser = response.user;
console.log(modifiedUser.loginMethods); // this will now contain the login method of the recipeUserId as well.
} else if (response.status === "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR") {
// This happens if there already exists another primary user with the same email or phone number
// as the recipeUserId's account.
} else if (response.status === "INPUT_USER_IS_NOT_A_PRIMARY_USER") {
// This happens if the input primaryUserId is not actually a primary user ID.
// You can call createPrimaryUserId and call linkAccountsAgain
} else if (response.status === "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR") {
// This happens if the input recipe user ID is already linked to another primary user.
// You can call unlink accounts on the recipe user ID and then try linking again.
}
}
note
Coming Soon
note
Coming Soon
#
Unlinking accountsIf you want to unlink an account from its primary user ID, you can use the following function:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import AccountLinking from "supertokens-node/recipe/accountlinking";
import { RecipeUserId } from "supertokens-node";
async function unlinkAccount(recipeUserId: RecipeUserId) {
let response = await AccountLinking.unlinkAccount(recipeUserId);
if (response.status === "OK") {
if (response.wasLinked) {
// This means that we unlinked the account from its primary user ID
} else {
// This means that the user was never linked in the first place
}
if (response.wasRecipeUserDeleted) {
// This is true if we call unlinkAccount on the recipe user ID of the primary user ID user.
// We delete this user because if we don't and we call getUserById() on this user's ID, SuperTokens
// won't know which user info to return - the primary user, or the recipe user.
// Note that even though the recipe user is deleted, the session, metadata, roles etc for this
// primary user is still intact, and calling getUserById(primaryUserId) will still return
// the user object with the other login methods.
} else {
// There not exists a user account which is not a primary user, with the recipeUserId = to the
// input recipeUserId.
}
}
}
note
Coming Soon
note
Coming Soon
#
Converting a string userId into a recipeUserIdIf you notice, the input to a lot of the functions above is of type RecipeUserId
. You can convert a string userID into a RecipeUserId
in the following way:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
async function getAsRecipeUserIdType(userId: string) {
return SuperTokens.convertToRecipeUserId(userId);
}
note
Coming Soon
note
Coming Soon
The reason we have this type is because it prevents bugs wherein a function is expecting a recipe user id (like createNewSession
, or updateEmailOrPassword
from email password recipe), but you pass in the primary user ID instead.
#
Other helper functionsOur SDK also exposes several other helper functions:
AccountLinking.createPrimaryUserIdOrLinkAccounts
: Given a recipe user ID, this function will attempt linking it with any primary user ID that has the same email or phone number associated with it. If no such primary user exists, this function will make the input user account a primary one.AccountLinking.getPrimaryUserThatCanBeLinkedToRecipeUserId
: Given a recipe user ID, this function will return a primary user ID which this user can be linked to, based on matching emails / phone numbers. If no such primary user exists, this function will returnundefined
.AccountLinking.canCreatePrimaryUser
: Given a recipe user ID, this function will return a statusOK
if the user can be made a primary user, and a different status otherwise (indicating why it can't become a primary user). A user can be made a primary user if there exists no other primary user with the same email or phone number across all the tenants that this user belongs to.AccountLinkling.canLinkAccounts
: Given a recipeUserId and a primary user ID, this function returns a statusOK
if the accounts can be linked, and if not, it returns a different status (indicating why the accounts can't be linked). Accounts can be linked if the recipe user ID is not already linked to another primary user, and if the resulting primary user does not have any email / phone number in common with another primary user across all of the tenants that it belongs to.AccountLinking.isSignUpAllowed
: Given the login info (email for example) of the new user, who is trying to sign up, this function returnstrue
if it's safe to allow them to sign up,false
otherwise. See the error codes in the automatic account linking page to see why this might returnfalse
.AccountLinking.isSignInAllowed
: Given the login info (email for example) of a user, who is trying to sign in, this function returnstrue
if it's safe to allow them to sign in,false
otherwise. See the error codes in the automatic account linking page to see why this might returnfalse
.AccountLinking.isEmailChangeAllowed
: Given the recipe user id and the new email for update, this function returnstrue
if it's safe to update the email, elsefalse
. Below are the conditions in whichfalse
is returned:- If the input recipe user is a primary user, then we need to check that the new email doesn't belong to any other primary user. If it does, we disallow the change since multiple primary user's can't have the same email.
- If the recipe user is NOT a primary user, and if the new email is not verified, then we check if there exists a primary user with the same email, and if it exists, we disallow the email change. We disallow because if this email is changed, and an email verification email is sent, then the primary user may end up clicking on the link by mistake, causing account linking to happen which can result in account take over if this recipe user is malicious.