---
title: Setting up the first factor
description: Set up the first authentication factor using SuperTokens with various frameworks.
sidebar:
  hidden: true
  order: 1
---

## 1. Initialisation

Start by following the recipe guide for the first factor. In this guide, we will take the example of `thirdparty` and `emailpassword` recipes as being the first factor.

After following the [backend quick setup section](/quickstart#2-integrate-the-backend-sdk) (or any of the framework specific integration guides), you should have all the auth APIs exposed to the frontend via the SuperTokens middleware. The `supertokens.init` code on the server would look like this:


<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
<DependentContent group="node-frameworks" label="Node.js framework">
<ContentOption title="Express" value="express">
```tsx
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "express",
  supertokens: {
    connectionURI: "<CORE_API_ENDPOINT>",
    apiKey: "<YOUR_API_KEY>",
  },
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [
    ThirdParty.init({
      //...
    }),
    EmailPassword.init({
      //...
    }),
    Session.init(), // initializes session features
    UserMetadata.init(), // initializes the user metadata feature
  ],
});
```
</ContentOption>
<ContentOption title="Hapi" value="hapi">
```tsx
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "hapi",
  supertokens: {
    connectionURI: "<CORE_API_ENDPOINT>",
    apiKey: "<YOUR_API_KEY>",
  },
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [
    ThirdParty.init({
      //...
    }),
    EmailPassword.init({
      //...
    }),
    Session.init(), // initializes session features
    UserMetadata.init(), // initializes the user metadata feature
  ],
});
```
</ContentOption>
<ContentOption title="Fastify" value="fastify">
```tsx
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "fastify",
  supertokens: {
    connectionURI: "<CORE_API_ENDPOINT>",
    apiKey: "<YOUR_API_KEY>",
  },
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [
    ThirdParty.init({
      //...
    }),
    EmailPassword.init({
      //...
    }),
    Session.init(), // initializes session features
    UserMetadata.init(), // initializes the user metadata feature
  ],
});
```
</ContentOption>
<ContentOption title="Koa" value="koa">
```tsx
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "koa",
  supertokens: {
    connectionURI: "<CORE_API_ENDPOINT>",
    apiKey: "<YOUR_API_KEY>",
  },
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [
    ThirdParty.init({
      //...
    }),
    EmailPassword.init({
      //...
    }),
    Session.init(), // initializes session features
    UserMetadata.init(), // initializes the user metadata feature
  ],
});
```
</ContentOption>
<ContentOption title="LoopBack" value="loopback">
```tsx
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "loopback",
  supertokens: {
    connectionURI: "<CORE_API_ENDPOINT>",
    apiKey: "<YOUR_API_KEY>",
  },
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/backend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [
    ThirdParty.init({
      //...
    }),
    EmailPassword.init({
      //...
    }),
    Session.init(), // initializes session features
    UserMetadata.init(), // initializes the user metadata feature
  ],
});
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/emailpassword"
	"github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels"
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/thirdparty"
	"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
	"github.com/supertokens/supertokens-golang/recipe/usermetadata"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
    apiBasePath := "/auth"
    websiteBasePath := "/auth"
	err := supertokens.Init(supertokens.TypeInput{
		Supertokens: &supertokens.ConnectionInfo{
            ConnectionURI: "<CORE_API_ENDPOINT>",
            APIKey: "<YOUR_API_KEY>",
		},
		AppInfo: supertokens.AppInfo{
            AppName: "<YOUR_APP_NAME>",
            APIDomain: "<YOUR_API_DOMAIN>",
            WebsiteDomain: "<YOUR_WEBSITE_DOMAIN>",
            APIBasePath: &apiBasePath,
            WebsiteBasePath: &websiteBasePath,
		},
		RecipeList: []supertokens.Recipe{
			thirdparty.Init(&tpmodels.TypeInput{ /*...*/ }),
			emailpassword.Init(&epmodels.TypeInput{ /*...*/ }),
			session.Init(nil), // initializes session features
            usermetadata.Init(nil), // initializes the user metadata feature
		},
	})

	if err != nil {
		panic(err.Error())
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-frameworks" label="Python framework">
<ContentOption title="FastAPI" value="fastapi">
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session, usermetadata

init(
    app_info=InputAppInfo(
        app_name="<YOUR_APP_NAME>",
        api_domain="<YOUR_API_DOMAIN>",
        website_domain="<YOUR_WEBSITE_DOMAIN>",
        api_base_path="/auth",
        website_base_path="/auth"
    ),
    supertokens_config=SupertokensConfig(
        connection_uri="<CORE_API_ENDPOINT>",
        api_key="<YOUR_API_KEY>"
    ),
    framework='fastapi',
    recipe_list=[
	    session.init(), # initializes session features
        usermetadata.init(), # initializes the user metadata feature
        thirdparty.init(
           # ...
        ),
        emailpassword.init(
            # ...
        )
    ],
    mode='asgi' # use wsgi if you are running using gunicorn
)
```
</ContentOption>
<ContentOption title="Flask" value="flask">
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session, usermetadata

init(
    app_info=InputAppInfo(
        app_name="<YOUR_APP_NAME>",
        api_domain="<YOUR_API_DOMAIN>",
        website_domain="<YOUR_WEBSITE_DOMAIN>",
        api_base_path="/auth",
        website_base_path="/auth"
    ),
    supertokens_config=SupertokensConfig(
        connection_uri="<CORE_API_ENDPOINT>",
        api_key="<YOUR_API_KEY>"
    ),
    framework='flask',
    recipe_list=[
	    session.init(), # initializes session features
        usermetadata.init(), # initializes the user metadata feature
        thirdparty.init(
           # ...
        ),
        emailpassword.init(
            # ...
        )
    ]
)
```
</ContentOption>
<ContentOption title="Django" value="django">
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session, usermetadata

init(
    app_info=InputAppInfo(
        app_name="<YOUR_APP_NAME>",
        api_domain="<YOUR_API_DOMAIN>",
        website_domain="<YOUR_WEBSITE_DOMAIN>",
        api_base_path="/auth",
        website_base_path="/auth"
    ),
    supertokens_config=SupertokensConfig(
        connection_uri="<CORE_API_ENDPOINT>",
        api_key="<YOUR_API_KEY>"
    ),
    framework='django',
    recipe_list=[
	    session.init(), # initializes session features
        usermetadata.init(), # initializes the user metadata feature
        thirdparty.init(
           # ...
        ),
        emailpassword.init(
            # ...
        )
    ],
    mode='asgi' # use wsgi if you are running django server in sync mode
)
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<DependentContent passive group="backend-language">
<ContentOption title="Node.js" value="nodejs">
{/*
<Tab title="Serverless">
:::note
Please refer the **serverless deployment** section in the ThirdParty + EmailPassword recipe guide
:::
</Tab>
<Tab title="Next.js">
:::note
Please refer the **NextJS** section in the ThirdParty + EmailPassword recipe guide
:::
</Tab>
<Tab title="Nestjs">
:::note
Please refer the **NestJS** section in the ThirdParty + EmailPassword recipe guide
:::
</Tab>
*/}
</ContentOption>
</DependentContent>

:::note[You should have also added the SuperTokens `middleware` and `errorHandler` (depending on your framework) to your application. We are not showing it in the above code snippet for brevity, but it is explained in the ThirdParty + EmailPassword recipe guide.]
:::

## 2. Adding second factor claim

After sign up or sign in of the first factor, the existence of the session signifies the completion of the first factor, but we want to explicitly mark the second factor as incomplete. This can be done by overriding the `createNewSession` function in the `Session.init` config:

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import Session from "supertokens-node/recipe/session";
import { BooleanClaim } from "supertokens-node/recipe/session/claims";

/*
This will be used to modify the session's access token payload
to add {"2fa-completed": false} into it.
*/
export const SecondFactorClaim = new BooleanClaim({
  fetchValue: () => false,
  key: "2fa-completed",
});

Session.init({
  override: {
    functions: (originalImplementation) => {
      return {
        ...originalImplementation,
        /* This function is called after signing in or signing up via the first factor */
        createNewSession: async function (input) {
          return originalImplementation.createNewSession({
            ...input,
            accessTokenPayload: {
              ...input.accessTokenPayload,
              ...(await SecondFactorClaim.build(
                input.userId,
                input.recipeUserId,
                input.tenantId,
                undefined,
                input.userContext,
              )),
            },
          });
        },
      };
    },
  },
});
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/session/claims"
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
	SecondFactorClaim, _ := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) {
		return false, nil
	}, nil)

	session.Init(&sessmodels.TypeInput{
		Override: &sessmodels.OverrideStruct{
			Functions: func(originalImplementation sessmodels.RecipeInterface) sessmodels.RecipeInterface {
				oCreateNewSession := *originalImplementation.CreateNewSession
				/* This function is called after signing in or signing up via the first factor */
				(*originalImplementation.CreateNewSession) = func(userID string, accessTokenPayload, sessionDataInDatabase map[string]interface{}, disableAntiCsrf *bool, tenantId string, userContext supertokens.UserContext) (sessmodels.SessionContainer, error) {
					if accessTokenPayload == nil {
						accessTokenPayload = map[string]interface{}{}
					}
					accessTokenPayload, err := SecondFactorClaim.Build(userID, tenantId, accessTokenPayload, userContext)
					if err != nil {
						return nil, err
					}
					return oCreateNewSession(userID, accessTokenPayload, sessionDataInDatabase, disableAntiCsrf, tenantId, userContext)
				}
				return originalImplementation
			},
		},
	})
}
```
</Tab>
<Tab title="Python" value="python">
```python
from supertokens_python.recipe import session
from supertokens_python.recipe.session.claims import BooleanClaim
from supertokens_python.recipe.session.interfaces import RecipeInterface
from typing import Any, Dict, Optional
from supertokens_python.types import RecipeUserId

# This will be used to modify the session's access token payload
# to add {"2fa-completed": false} into it.
SecondFactorClaim = BooleanClaim(
    key="2fa-completed", fetch_value=lambda _, __, ___, ____, _____: False
)


def override_session_functions(original_implementation: RecipeInterface):
    original_create_new_session = original_implementation.create_new_session

    async def create_new_session(
        user_id: str,
        recipe_user_id: RecipeUserId,
        access_token_payload: Optional[Dict[str, Any]],
        session_data_in_database: Optional[Dict[str, Any]],
        disable_anti_csrf: Optional[bool],
        tenant_id: str,
        user_context: Dict[str, Any],
    ):
        # This function is called after signing in or signing up via the first factor

        if access_token_payload is None:
            access_token_payload = {}

        access_token_payload = {
            **access_token_payload,
            **(
                await SecondFactorClaim.build(
                    user_id,
                    recipe_user_id,
                    tenant_id,
                    access_token_payload,
                    user_context,
                )
            ),
        }
        return await original_create_new_session(
            user_id,
            recipe_user_id,
            access_token_payload,
            session_data_in_database,
            disable_anti_csrf,
            tenant_id,
            user_context,
        )

    original_implementation.create_new_session = create_new_session
    return original_implementation


session.init(
    override=session.InputOverrideConfig(functions=override_session_functions)
)
```
</Tab>
</CodeGroup>

We add `SecondFactorClaim` into the access token payload. This will be set to false on session creation (see `fetchValue` in the claim definition).
