Post signin / signup callbacks
#
1) On the frontend- ReactJS
- Angular
- Vue
Important
supertokens-auth-react
SDK and will inject the React components to show the UI. Therefore, the code snippet below refers to the supertokens-auth-react
SDK.This method allows you to fire events immediately after a successful sign in. For example to send analytics events post sign in.
import SuperTokens from "supertokens-auth-react";
import ThirdPartyPasswordless from "supertokens-auth-react/recipe/thirdpartypasswordless";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdPartyPasswordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
if (context.action === "SESSION_ALREADY_EXISTS") {
// TODO:
} else if (context.action === "PASSWORDLESS_RESTART_FLOW") {
// TODO:
} else if (context.action === "PASSWORDLESS_CODE_SENT") {
// TODO:
} else if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
if ("phoneNumber" in context.user) {
const { phoneNumber } = context.user;
} else {
const { emails } = context.user;
}
// TODO: Sign up
} else {
// TODO: Sign in
}
}
}
}),
Session.init()
]
});
info
Please refer to this page to learn more about the onHandleEvent
hook.
Important
supertokens-auth-react
SDK and will inject the React components to show the UI. Therefore, the code snippet below refers to the supertokens-auth-react
SDK.This method allows you to fire events immediately after a successful sign in. For example to send analytics events post sign in.
import SuperTokens from "supertokens-auth-react";
import ThirdPartyPasswordless from "supertokens-auth-react/recipe/thirdpartypasswordless";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdPartyPasswordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
if (context.action === "SESSION_ALREADY_EXISTS") {
// TODO:
} else if (context.action === "PASSWORDLESS_RESTART_FLOW") {
// TODO:
} else if (context.action === "PASSWORDLESS_CODE_SENT") {
// TODO:
} else if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
if ("phoneNumber" in context.user) {
const { phoneNumber } = context.user;
} else {
const { emails } = context.user;
}
// TODO: Sign up
} else {
// TODO: Sign in
}
}
}
}),
Session.init()
]
});
info
Please refer to this page to learn more about the onHandleEvent
hook.
This method allows you to fire events immediately after a successful sign in. For example to send analytics events post sign in.
import SuperTokens from "supertokens-auth-react";
import ThirdPartyPasswordless from "supertokens-auth-react/recipe/thirdpartypasswordless";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdPartyPasswordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
if (context.action === "SESSION_ALREADY_EXISTS") {
// TODO:
} else if (context.action === "PASSWORDLESS_RESTART_FLOW") {
// TODO:
} else if (context.action === "PASSWORDLESS_CODE_SENT") {
// TODO:
} else if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
if ("phoneNumber" in context.user) {
const { phoneNumber } = context.user;
} else {
const { emails } = context.user;
}
// TODO: Sign up
} else {
// TODO: Sign in
}
}
}
}),
Session.init()
]
});
info
Please refer to this page to learn more about the onHandleEvent
hook.
#
2) On the backendFor this, you'll have to override the consumeCode
and thirdPartySignInUp
recipe functions in the init
function call.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
import ThirdPartyPasswordless from "supertokens-node/recipe/thirdpartypasswordless";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdPartyPasswordless.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,
// override the thirdparty sign in / up API
thirdPartySignInUp: async function (input) {
// TODO: Some pre sign in / up logic
let response = await originalImplementation.thirdPartySignInUp(input);
if (response.status === "OK") {
let { id, emails } = response.user;
// This is the response from the OAuth 2 provider that contains their tokens or user info.
let providerAccessToken = response.oAuthTokens["access_token"];
let firstName = response.rawUserInfoFromProvider.fromUserInfoAPI!["first_name"];
if (input.session === undefined) {
if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
// TODO: Post sign up logic
} else {
// TODO: Post sign in logic
}
}
}
return response;
},
consumeCode: async (input) => {
// First we call the original implementation of consumeCodePOST.
const response = await originalImplementation.consumeCode(input);
// Post sign up response, we check if it was successful
if (response.status === "OK") {
if ("phoneNumber" in response.user) {
const { id, phoneNumbers } = response.user;
} else {
const { id, emails } = response.user;
}
if (input.session === undefined) {
if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
// TODO: post sign up logic
} else {
// TODO: post sign in logic
}
}
}
return response;
}
}
}
}
}),
Session.init({ /* ... */ })
]
});
import (
"fmt"
"github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/recipe/thirdpartypasswordless"
"github.com/supertokens/supertokens-golang/recipe/thirdpartypasswordless/tplmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
thirdpartypasswordless.Init(tplmodels.TypeInput{
Override: &tplmodels.OverrideStruct{
Functions: func(originalImplementation tplmodels.RecipeInterface) tplmodels.RecipeInterface {
// create a copy of the original function
originalConsumeCode := *originalImplementation.ConsumeCode
originalThirdPartySignInUp := *originalImplementation.ThirdPartySignInUp
// override the thirdparty sign in / up function
(*originalImplementation.ThirdPartySignInUp) = func(thirdPartyID string, thirdPartyUserID string, email string, oAuthTokens map[string]interface{}, rawUserInfoFromProvider tpmodels.TypeRawUserInfoFromProvider, tenantId string, userContext *map[string]interface{}) (tplmodels.ThirdPartySignInUp, error) {
// TODO: some pre sign in / up logic
resp, err := originalThirdPartySignInUp(thirdPartyID, thirdPartyUserID, email, oAuthTokens, rawUserInfoFromProvider, tenantId, userContext)
if err != nil {
return tplmodels.ThirdPartySignInUp{}, err
}
if resp.OK != nil {
// user object contains the ID and email of the user
user := resp.OK.User
fmt.Println(user)
if resp.OK.CreatedNewUser {
// TODO: Post sign up logic
} else {
// TODO: Post sign in logic
}
}
return resp, err
}
// override the passwordless sign in up function
(*originalImplementation.ConsumeCode) = func(userInput *plessmodels.UserInputCodeWithDeviceID, linkCode *string, preAuthSessionID string, tenantId string, userContext supertokens.UserContext) (tplmodels.ConsumeCodeResponse, error) {
// First we call the original implementation of ConsumeCodeUp.
response, err := originalConsumeCode(userInput, linkCode, preAuthSessionID, tenantId, userContext)
if err != nil {
return tplmodels.ConsumeCodeResponse{}, err
}
if response.OK != nil {
// sign in was successful
// user object contains the ID and email or phone number
user := response.OK.User
fmt.Println(user)
if response.OK.CreatedNewUser {
// TODO: Post sign up logic
} else {
// TODO: Post sign in logic
}
}
return response, nil
}
return originalImplementation
},
},
}),
},
})
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import thirdpartypasswordless, session, passwordless
from supertokens_python.recipe.thirdpartypasswordless.interfaces import RecipeInterface, ConsumeCodeOkResult
from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
from typing import Dict, Any, Union
def override_thirdpartypasswordless_functions(original_implementation: RecipeInterface) -> RecipeInterface:
original_thirdparty_sign_in_up = original_implementation.thirdparty_sign_in_up
original_consume_code = original_implementation.consume_code
async def thirdparty_sign_in_up(
third_party_id: str,
third_party_user_id: str,
email: str,
oauth_tokens: Dict[str, Any],
raw_user_info_from_provider: RawUserInfoFromProvider,
tenant_id: str,
user_context: Dict[str, Any]
):
result = await original_thirdparty_sign_in_up(third_party_id, third_party_user_id, email, oauth_tokens, raw_user_info_from_provider, tenant_id, user_context)
# user object contains the ID and email of the user
user = result.user
print(user)
# This is the response from the OAuth 2 provider that contains their tokens or user info.
provider_access_token = result.oauth_tokens["access_token"]
print(provider_access_token)
if result.raw_user_info_from_provider.from_user_info_api is not None:
first_name = result.raw_user_info_from_provider.from_user_info_api["first_name"]
print(first_name)
if result.created_new_user:
print("New user was created")
# TODO: Post sign up logic
else:
print("User already existed and was signed in")
# TODO: Post sign in logic
return result
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
print(id)
if result.user.phone_number is not None:
phone_number = result.user.phone_number
print(phone_number)
else:
email = result.user.email
print(email)
if result.created_new_user:
# TODO: post sign up logic
pass
else:
# TODO: post sign in logic
pass
return result
original_implementation.thirdparty_sign_in_up = thirdparty_sign_in_up
original_implementation.consume_code = consume_code
return original_implementation
init(
app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
framework='...',
recipe_list=[
thirdpartypasswordless.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
override=thirdpartypasswordless.InputOverrideConfig(
functions=override_thirdpartypasswordless_functions
),
providers=[]
),
session.init(),
]
)
Using the code above, if createdNewUser
is true
, you can (for example):
- Add the user's ID and their info to your own database (in addition to it being stored in SuperTokens).
- Send analytics events about a sign up.
- Send a welcome email to the user.
- You can associate a role to the user.