Post signin / signup callbacks
#
1) On the frontend- ReactJS
- Angular
- Vue
This method allows you to fire events immediately after a successful sign in. For example to send analytics events post sign in.
// this goes in the auth route config of your frontend app (once the pre built UI script has been loaded)
(window as any).supertokensUIInit("supertokensui", {
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
(window as any).supertokensUIPasswordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
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
}
}
}
}),
(window as any).supertokensUIThirdParty.init({
onHandleEvent: async (context) => {
if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
// TODO: Sign up
} else {
// TODO: Sign in
}
}
}
}),
(window as any).supertokensUISession.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 Passwordless from "supertokens-auth-react/recipe/passwordless";
import ThirdParty from "supertokens-auth-react/recipe/thirdparty";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
Passwordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
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
}
}
}
}),
ThirdParty.init({
onHandleEvent: async (context) => {
if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
// 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.
// this goes in the auth route config of your frontend app (once the pre built UI script has been loaded)
(window as any).supertokensUIInit("supertokensui", {
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
(window as any).supertokensUIPasswordless.init({
contactMethod: "EMAIL_OR_PHONE",
onHandleEvent: async (context) => {
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
}
}
}
}),
(window as any).supertokensUIThirdParty.init({
onHandleEvent: async (context) => {
if (context.action === "SUCCESS") {
if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
// TODO: Sign up
} else {
// TODO: Sign in
}
}
}
}),
(window as any).supertokensUISession.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 signInUp
recipe functions in the init
function call.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
import ThirdParty from "supertokens-node/recipe/thirdparty"
import Passwordless from "supertokens-node/recipe/passwordless"
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdParty.init({
override: {
functions: (originalImplementation) => {
return {
...originalImplementation,
// override the thirdparty sign in / up API
signInUp: async function (input) {
// TODO: Some pre sign in / up logic
let response = await originalImplementation.signInUp(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;
}
}
}
}
}),
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.
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"
"github.com/supertokens/supertokens-golang/recipe/passwordless/plessmodels"
"github.com/supertokens/supertokens-golang/recipe/thirdparty"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
thirdparty.Init(&tpmodels.TypeInput{
Override: &tpmodels.OverrideStruct{
Functions: func(originalImplementation tpmodels.RecipeInterface) tpmodels.RecipeInterface {
// create a copy of the original function
originalSignInUp := *originalImplementation.SignInUp
// override the thirdparty sign in / up function
(*originalImplementation.SignInUp) = func(thirdPartyID, thirdPartyUserID, email string, oAuthTokens tpmodels.TypeOAuthTokens, rawUserInfoFromProvider tpmodels.TypeRawUserInfoFromProvider, tenantId string, userContext supertokens.UserContext) (tpmodels.SignInUpResponse, error) {
// TODO: some pre sign in / up logic
resp, err := originalSignInUp(thirdPartyID, thirdPartyUserID, email, oAuthTokens, rawUserInfoFromProvider, tenantId, userContext)
if err != nil {
return tpmodels.SignInUpResponse{}, 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
}
return originalImplementation
},
},
}),
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 passwordless 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 ConsumeCode.
response, err := originalConsumeCode(userInput, linkCode, preAuthSessionID, tenantId, userContext)
if err != nil {
return plessmodels.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 passwordless, session, thirdparty
from supertokens_python.recipe.passwordless.interfaces import (
RecipeInterface as PasswordlessRecipeInterface,
ConsumeCodeOkResult,
)
from supertokens_python.recipe.thirdparty.interfaces import (
RecipeInterface as ThirdPartyRecipeInterface,
SignInUpOkResult,
)
from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
from typing import Dict, Any, Union, Optional
from supertokens_python.recipe.session.interfaces import SessionContainer
def override_passwordless_functions(
original_implementation: PasswordlessRecipeInterface,
) -> PasswordlessRecipeInterface:
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],
session: Optional[SessionContainer],
should_try_linking_with_session_user: Union[bool, None],
tenant_id: str,
user_context: Dict[str, Any],
):
# First we call the original implementation of consume_code.
result = await original_consume_code(
pre_auth_session_id,
user_input_code,
device_id,
link_code,
session,
should_try_linking_with_session_user,
tenant_id,
user_context,
)
# Post sign up response, we check if it was successful
if isinstance(result, ConsumeCodeOkResult):
id = result.user.id
print(id)
if session is None:
if (
result.created_new_recipe_user
and len(result.user.login_methods) == 1
):
# TODO: post sign up logic
pass
else:
# TODO: post sign in logic
pass
return result
original_implementation.consume_code = consume_code
return original_implementation
def override_thirdparty_functions(
original_implementation: ThirdPartyRecipeInterface,
) -> ThirdPartyRecipeInterface:
original_thirdparty_sign_in_up = original_implementation.sign_in_up
async def thirdparty_sign_in_up(
third_party_id: str,
third_party_user_id: str,
email: str,
is_verified: bool,
oauth_tokens: Dict[str, Any],
raw_user_info_from_provider: RawUserInfoFromProvider,
session: Optional[SessionContainer],
should_try_linking_with_session_user: Union[bool, None],
tenant_id: str,
user_context: Dict[str, Any],
):
result = await original_thirdparty_sign_in_up(
third_party_id,
third_party_user_id,
email,
is_verified,
oauth_tokens,
raw_user_info_from_provider,
session,
should_try_linking_with_session_user,
tenant_id,
user_context,
)
if isinstance(result, SignInUpOkResult):
# 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 session is None:
if (
result.created_new_recipe_user
and len(result.user.login_methods) == 1
):
# TODO: post sign up logic
pass
else:
# TODO: post sign in logic
pass
return result
original_implementation.sign_in_up = thirdparty_sign_in_up
return original_implementation
init(
app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
framework="...",
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
override=passwordless.InputOverrideConfig(
functions=override_passwordless_functions
),
),
thirdparty.init(
override=thirdparty.InputOverrideConfig(
functions=override_thirdparty_functions
)
),
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.