-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #763 from supertokens/mfa
MFA docs
- Loading branch information
Showing
192 changed files
with
11,957 additions
and
886 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import CustomAdmonition from "/src/components/customAdmonition" | ||
|
||
<CustomAdmonition type="paid-feature"> | ||
|
||
This is a paid feature. | ||
|
||
For self hosted users, [Sign up](https://supertokens.com/auth) to get a license key and follow the instructions sent to you by email. Using the dev license key is free. We only start charging you once you enable the feature in production using the provided production license key. | ||
|
||
For managed service users, you can click on the "enable paid features" button on [our dashboard](https://supertokens.com/dashboard-saas), and follow the steps from there on. Once enabled, this feature is free on the provided development environment. | ||
|
||
</CustomAdmonition> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
191 changes: 191 additions & 0 deletions
191
...ilpassword/common-customizations/account-linking/adding-accounts-to-session.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
--- | ||
id: adding-accounts-to-session | ||
title: Linking social accounts to an existing account | ||
hide_title: true | ||
--- | ||
|
||
import AccountLinkingPaidBanner from '../../../community/reusableMD/accountlinking/AccountLinkingPaidBanner.mdx' | ||
import BackendSDKTabs from "/src/components/tabs/BackendSDKTabs"; | ||
|
||
<AccountLinkingPaidBanner /> | ||
|
||
# Linking social accounts to an existing account | ||
|
||
There may be scenarios in which you want to link a social account to an existing user account. This guide will walk you through how to do this. | ||
|
||
The idea here is that we reuse the existing sign up APIs, but call them with a session's access token. The APIs will then create a new recipe user for that login method based on the input, and then link that to the session user. Of course, there are security checks done to ensure there is no account takeover risk, and we will go through them in this guide as well. | ||
|
||
:::caution | ||
We do not provide pre built UIs for this flow since it's probably something you want to add in your settings page or during the sign up process, so this guide will focus on which APIs to call from your own UI. | ||
|
||
The frontend code snippets below refer to the `supertokens-web-js` SDK. You can continue to use this even if you have initialised our `supertokens-auth-react` SDK, on the frontend. | ||
::: | ||
|
||
## Linking a social account to an existing user account | ||
|
||
### Step 1: Enable account linking and third party on the backend SDK | ||
|
||
<BackendSDKTabs> | ||
<TabItem value="nodejs"> | ||
|
||
```tsx | ||
import supertokens, { User, RecipeUserId } from "supertokens-node"; | ||
import AccountLinking from "supertokens-node/recipe/accountlinking"; | ||
import { AccountInfoWithRecipeId } from "supertokens-node/recipe/accountlinking/types"; | ||
import { SessionContainerInterface } from "supertokens-node/recipe/session/types"; | ||
import ThirdParty from "supertokens-node/recipe/thirdparty"; | ||
|
||
supertokens.init({ | ||
supertokens: { | ||
connectionURI: "...", | ||
apiKey: "..." | ||
}, | ||
appInfo: { | ||
apiDomain: "...", | ||
appName: "...", | ||
websiteDomain: "..." | ||
}, | ||
recipeList: [ | ||
// highlight-start | ||
ThirdParty.init({ /* ...*/ }), | ||
AccountLinking.init({ | ||
shouldDoAutomaticAccountLinking: async (newAccountInfo: AccountInfoWithRecipeId & { recipeUserId?: RecipeUserId }, user: User | undefined, session: SessionContainerInterface | undefined, tenantId: string, userContext: any) => { | ||
if (user === undefined) { | ||
return { | ||
shouldAutomaticallyLink: true, | ||
shouldRequireVerification: true | ||
} | ||
} | ||
if (session !== undefined && session.getUserId() === user.id) { | ||
return { | ||
shouldAutomaticallyLink: true, | ||
shouldRequireVerification: true | ||
} | ||
} | ||
return { | ||
shouldAutomaticallyLink: false | ||
} | ||
} | ||
}) | ||
// highlight-end | ||
] | ||
}); | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="go"> | ||
|
||
:::note | ||
Coming Soon | ||
::: | ||
|
||
</TabItem> | ||
<TabItem value="python"> | ||
|
||
:::note | ||
Coming Soon | ||
::: | ||
|
||
</TabItem> | ||
</BackendSDKTabs> | ||
|
||
In the above implementation of `shouldDoAutomaticAccountLinking`, we only allow account linking if the input session is present. This means that we are trying to link a social login account to an existing session user. Otherwise, we do not allow account linking which means that first factor account linking is disabled. If you want to enable that too, you can see [this page](./automatic-account-linking). | ||
|
||
Read the [third party recipe docs](/docs/thirdparty/common-customizations/sign-in-and-up/built-in-providers#step-2-adding-providers-config-to-the-backend) to learn how to add provider config. | ||
|
||
### Step 2: Create a UI to show social login buttons and handle login | ||
|
||
First, you will need to detect which social login methods are already linked to the user. This can be done by inspecting the [user object](../../user-object) on the backend and checking the `thirdParty.id` property (the values will be like `google`, `facebook` etc). | ||
|
||
Then you will have to create your own UI which asks the user to pick a social login provider to connect to. Once they click on one, you will redirect them to that provider's page. Post login, the provider will redirect the user back to your application (on the same path as the first factor login) after which you will call our APIs to consume the OAuth tokens and link the user. | ||
|
||
The exact implementation of the above can be found [here](/docs/thirdparty/custom-ui/thirdparty-login). The two big differences in the implementation are: | ||
- When you call the signinup API, you need to provide the session's access token in the request. If you are using our frontend SDK, this is done automatically via our frontend network interceptors. The access token will enable the backend to get a session and then link the social login account to session user. | ||
- There are new types of failure scenarios when calling the signinup API which are not possible during first factor login. To learn more about them, see the [error codes section](/docs/thirdparty/common-customizations/account-linking/automatic-account-linking#err_code_001) (> `ERR_CODE_008`). | ||
|
||
### Step 3: Extract the social login access token and user peofile info on the backend | ||
|
||
Once you call the signinup API from the frontend, SuperTokens will verify the OAuth tokens and fetch the user's profile info from the third party provider. SuperTokens will also link the newly created recipe user to the session user. | ||
|
||
To fetch the new user object and also the third party profile, you can override the signinup recipe function: | ||
|
||
<BackendSDKTabs> | ||
<TabItem value="nodejs"> | ||
|
||
```tsx | ||
import SuperTokens, { User } from "supertokens-node"; | ||
import ThirdParty from "supertokens-node/recipe/thirdparty"; | ||
import Session from "supertokens-node/recipe/session"; | ||
|
||
SuperTokens.init({ | ||
appInfo: { | ||
apiDomain: "...", | ||
appName: "...", | ||
websiteDomain: "..." | ||
}, | ||
supertokens: { | ||
connectionURI: "...", | ||
}, | ||
recipeList: [ | ||
ThirdParty.init({ | ||
// highlight-start | ||
override: { | ||
functions: (originalImplementation) => { | ||
return { | ||
...originalImplementation, | ||
// override the thirdparty sign in / up function | ||
signInUp: async function (input) { | ||
|
||
let existingUser: User | undefined = undefined; | ||
if (input.session !== undefined) { | ||
existingUser = await SuperTokens.getUser(input.session.getUserId()); | ||
} | ||
|
||
let response = await originalImplementation.signInUp(input); | ||
|
||
if (response.status === "OK") { | ||
|
||
let accessToken = response.oAuthTokens["access_token"]; | ||
|
||
let firstName = response.rawUserInfoFromProvider.fromUserInfoAPI!["first_name"]; | ||
|
||
if (input.session !== undefined && response.user.id === input.session.getUserId()) { | ||
if (response.user.loginMethods.length === existingUser!.loginMethods.length + 1) { | ||
// new social account was linked to session user | ||
} else { | ||
// social account was already linked to the session | ||
// user from before | ||
} | ||
} | ||
} | ||
|
||
return response; | ||
} | ||
} | ||
} | ||
} | ||
// highlight-end | ||
}), | ||
Session.init({ /* ... */ }) | ||
] | ||
}); | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="go"> | ||
|
||
:::note | ||
Coming Soon | ||
::: | ||
|
||
</TabItem> | ||
<TabItem value="python"> | ||
|
||
:::note | ||
Coming Soon | ||
::: | ||
|
||
</TabItem> | ||
</BackendSDKTabs> | ||
|
||
Notice in the above snippet that we check for `input.session !== undefined && response.user.id === input.session.getUserId()`. This ensures that we run our custom logic only if it's linking a social account to your session account, and not during first factor login. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.