---
title: Hooks and overrides
description: Add custom logic in the authentication flow by overriding the SuperTokens APIs.
sidebar:
  order: 50
---

**SuperTokens** exposes a set of constructs that allow you to trigger different actions during the authentication lifecycle or to even fully customize the logic based on your use case.
The following sections describe how you can adjust the `passwordless` recipe to your needs.

Explore the [references pages](/references) for a more in depth guide on hooks and overrides.

## Frontend hook

<UITypeSwitch />

<VariantContent storageKey="ui-type" value="prebuilt">

This method gets fired, after certain events in the `passwordles` authentication flow.
Use it to fire different types of events immediately and introduce custom logic based on your use case.

<CodeGroup group="frontend-prebuilt-ui">
<Tab title="Reactjs" value="reactjs">
```tsx
import SuperTokens from "supertokens-auth-react";
import Passwordless from "supertokens-auth-react/recipe/passwordless";
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 {
          let { id, emails, phoneNumbers } = context.user;
          if (context.action === "SUCCESS") {
            if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
              // TODO: Sign up
            } else {
              // TODO: Sign in
            }
          }
        }
      },
    }),
    Session.init(),
  ],
});
```
</Tab>
<Tab title="Angular" value="angular">
```tsx check=false reason="This example omits surrounding application and SuperTokens configuration."
// this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded)

supertokensUIInit({
  appInfo: {
    apiDomain: "...",
    appName: "...",
    websiteDomain: "...",
  },
  recipeList: [
    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 {
          let { id, emails, phoneNumbers } = context.user;
          if (context.action === "SUCCESS") {
            if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
              // TODO: Sign up
            } else {
              // TODO: Sign in
            }
          }
        }
      },
    }),
    supertokensUISession.init(),
  ],
});
```
</Tab>
</CodeGroup>

</VariantContent>

<VariantContent storageKey="ui-type" value="custom">

:::warning[Not applicable]
This section is not applicable for custom UI since you are calling the consume code API yourself anyway. You can perform any actions post sign in / up based on the result of the API call.
:::

</VariantContent>

## Backend override

Overriding the `consumeCode` function allows you to introduce your own logic for the authentication process.
Use it to persist different types of data or trigger actions.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import SuperTokens from "supertokens-node";
import Passwordless from "supertokens-node/recipe/passwordless";
import Session from "supertokens-node/recipe/session";

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 (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({
      /* ... */
    }),
  ],
});
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"fmt"

	"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 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
					},
				},
			}),
		},
	})
}
```
</Tab>
<Tab title="Python" value="python">
```python check=false reason="This example omits surrounding application and SuperTokens configuration."
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session, passwordless
from supertokens_python.recipe.passwordless.interfaces import (
    RecipeInterface,
    ConsumeCodeOkResult,
)
from typing import Dict, Any, Union, Optional
from supertokens_python.recipe.session.interfaces import SessionContainer


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],
        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 session is None:
            if (
                isinstance(result, ConsumeCodeOkResult)
                and len(result.user.login_methods) == 1
            ):
                if result.created_new_recipe_user:
                    # TODO: post sign up logic
                    pass
                else:
                    # TODO: post sign in logic
                    pass

        return result

    original_implementation.consume_code = consume_code

    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
            ),
        ),
        session.init(),
    ],
)
```
</Tab>
</CodeGroup>


---

## See also

<CardGroup cols={3}>
  <Card title="Frontend function overrides" href="/references/frontend-sdks/function-overrides" />
  <Card title="Frontend hooks" href="/references/frontend-sdks/hooks" />
  <Card title="React component override" href="/references/frontend-sdks/prebuilt-ui/override-react-components" />
  <Card title="Backend function overrides" href="/references/backend-sdks/function-overrides" />
  <Card title="Backend API overrides" href="/references/backend-sdks/api-overrides" />
  <Card title="Email and SMS behavior" href="/authentication/passwordless/configure-email-and-sms-behavior" />
  <Card title="Invite link sign up" href="/authentication/passwordless/invite-link-flow" />
  <Card title="Allow list sign up" href="/authentication/passwordless/allow-list-flow" />
</CardGroup>
