Skip to content

Commit

Permalink
finishes docs
Browse files Browse the repository at this point in the history
  • Loading branch information
rishabhpoddar committed Nov 9, 2023
1 parent a5a7bd0 commit 1a9f3bb
Showing 1 changed file with 197 additions and 2 deletions.
199 changes: 197 additions & 2 deletions v2/passwordless/common-customizations/userid-format.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,200 @@ title: Assigning custom user IDs
hide_title: true
---

<!-- COPY DOCS -->
<!-- ./thirdpartyemailpassword/common-customizations/userid-format.mdx -->

import BackendSDKTabs from "/src/components/tabs/BackendSDKTabs"
import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

# Assigning custom user IDs

This feature allows you to change the default SuperTokens user ID (UUID v4) to a value that you prefer. There are two primary use cases for this:
- Use case 1: During [migration of users](../migration/account-creation/user-id-mapping)
- Use case 2: If you prefer a different user ID format than the default one.

The way this feature works is that SuperTokens will store and manage the user ID mapping in the SuperTokens core. So when that users logs in, you will get back the mapped (the custom) user ID instead of the SuperTokens user ID.

Features like user roles, user metadata, session will also all work based on the custom user ID.

## Use case 1: Migration of users
This topic is better covered [under the migration section](../migration/account-creation/user-creation). The main purpose of this is that you can retain the existing user IDs of your users when migrating them to SuperTokens. This makes it easier to migrate users without having to update the user IDs in your database.

## Use case 2: If you prefer a different user ID format than the default one.

You can call the user ID mapping function post sign up as shown below. It is important to know that user ID mapping can only be done, before there is any other data (session, roles etc) associated with the user.

<BackendSDKTabs>
<TabItem value="nodejs">

```tsx
import SuperTokens from "supertokens-node";
import Passwordless from "supertokens-node/recipe/passwordless";
import Session from "supertokens-node/recipe/session";
import { RecipeUserId } from "supertokens-node";

SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
Passwordless.init({
contactMethod: "EMAIL", // This example will work with any contactMethod
flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType
override: {
functions: (originalImplementation) => {
return {
...originalImplementation,
consumeCode: async (input) => {

// First we call the original implementation of consumeCode.
let response = await originalImplementation.consumeCode(input);

// Post sign up response, we check if it was successful
if (response.status === "OK") {
let { id, emails, phoneNumbers } = response.user;

if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
// highlight-start
let externalUserId = "<CUSTOM USER ID>"
await SuperTokens.createUserIdMapping({ superTokensUserId: response.user.id, externalUserId })

// we modify the response object to have the custom user ID.
response.user.id = externalUserId
response.user.loginMethods[0].recipeUserId = new RecipeUserId(externalUserId);
// highlight-end
}
}
return response;
}
}
}
}
}),
Session.init({ /* ... */ })
]
});
```
</TabItem>
<TabItem value="go">

```go
import (
"github.com/supertokens/supertokens-golang/recipe/passwordless"
"github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {

supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
passwordless.Init(plessmodels.TypeInput{
Override: &plessmodels.OverrideStruct{
Functions: func(originalImplementation plessmodels.RecipeInterface) plessmodels.RecipeInterface {
// create a copy of the original function
originalConsumeCode := *originalImplementation.ConsumeCode

// override the sign in up function
(*originalImplementation.ConsumeCode) = func(userInput *plessmodels.UserInputCodeWithDeviceID, linkCode *string, preAuthSessionID string, tenantId string, userContext supertokens.UserContext) (plessmodels.ConsumeCodeResponse, error) {

// First we call the original implementation of ConsumeCodeUp.
response, err := originalConsumeCode(userInput, linkCode, preAuthSessionID, tenantId, userContext)
if err != nil {
return plessmodels.ConsumeCodeResponse{}, err
}

if response.OK != nil {
if response.OK.CreatedNewUser {
// highlight-start
externalUserId := "<CUSTOM USER ID>"
_, err := supertokens.CreateUserIdMapping(response.OK.User.ID, externalUserId, nil, nil)
if err != nil {
return plessmodels.ConsumeCodeResponse{}, err
}
response.OK.User.ID = externalUserId
// highlight-end
}

}
return response, nil
}

return originalImplementation
},
},
}),
},
})
}
```

</TabItem>
<TabItem value="python">

```python
from supertokens_python import init, InputAppInfo
from supertokens_python.asyncio import create_user_id_mapping
from supertokens_python.recipe import session, passwordless
from supertokens_python.recipe.passwordless.interfaces import RecipeInterface, ConsumeCodeOkResult
from typing import Dict, Any, Union

def override_passwordless_functions(original_implementation: RecipeInterface) -> RecipeInterface:
original_consume_code = original_implementation.consume_code

async def consume_code(
pre_auth_session_id: str,
user_input_code: Union[str, None],
device_id: Union[str, None],
link_code: Union[str, None],
tenant_id: str,
user_context: Dict[str, Any]
):
# First we call the original implementation of consumeCodePOST.
result = await original_consume_code(pre_auth_session_id, user_input_code, device_id, link_code, tenant_id, user_context)

# Post sign up response, we check if it was successful
if isinstance(result, ConsumeCodeOkResult):
id = result.user.user_id
phone_number = result.user.phone_number
email = result.user.email
print(id)
print(phone_number)
print(email)

if result.created_new_user:
# highlight-start
external_user_id = "<CUSTOM USER ID>"
await create_user_id_mapping(result.user.user_id, external_user_id)
result.user.user_id = external_user_id
# highlight-end

return result

original_implementation.consume_code = consume_code

return original_implementation

init(
app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
framework='...', # type: ignore
recipe_list=[
passwordless.init(
contact_config=passwordless.ContactConfig(
contact_method="EMAIL", # This example will work with any contactMethod
),
flow_type="USER_INPUT_CODE_AND_MAGIC_LINK", # This example will work with any flowType
# highlight-start
override=passwordless.InputOverrideConfig(
functions=override_passwordless_functions
),
# highlight-end
),
session.init(),
]
)
```

</TabItem>
</BackendSDKTabs>

0 comments on commit 1a9f3bb

Please sign in to comment.