Adding Extra Fields
Step 1: Front End#
Currently, your Sign-up form contains only email and password fields. But you might want to get more information from your customers on sign up. Let's see how you can extend the Sign-up form to fit your needs.
- ReactJS
- Angular
- Vue
- Plain JavaScript
- React Native
Note
supertokens-web-js SDK which exposes several helper functions that query the APIs exposed by the SuperTokens backend SDK.You can refer to this example app as a reference for using the
supertokens-web-js SDK.Note
supertokens-react-native SDK. The SDK provides session management features.To add login functionality, you need to build your own UI and call the APIs exposed by the backend SDKs. You can find the API spec here
import SuperTokens from "supertokens-auth-react";
import ThirdPartyEmailPassword from "supertokens-auth-react/recipe/thirdpartyemailpassword";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        ThirdPartyEmailPassword.init({
            signInAndUpFeature: {
                signUpForm: {
                    formFields: [{
                        id: "name",
                        label: "Full name",
                        placeholder: "First name and last name"
                    }, {
                        id: "age",
                        label: "Your age",
                        placeholder: "How old are you?",
                    }, {
                        id: "country",
                        label: "Your country",
                        placeholder: "Where do you live?",
                        optional: true
                    }]
                }
            }
        }),
        Session.init()
    ]
});

Step 2: Back End#
Add fields to SuperTokens init#
Now that you have added new fields to the front end you need to make sure that the backend will take them into account when your new users register.
Go back to where you have called the SuperTokens init function in your backend code:
- NodeJS
- GoLang
- Python
import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
  appInfo: {
    apiDomain: "...",
    appName: "...",
    websiteDomain: "..."
  },
  supertokens: {
    connectionURI: "...",
  },
  recipeList: [
    ThirdPartyEmailPassword.init({
      signUpFeature: {
        formFields: [{
          id: "name"
        }, {
          id: "age"
        }, {
          id: "country",
          optional: true
        }]
      }
    }),
    Session.init({ /* ... */ })
  ]
});
import (
    "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels"
    "github.com/supertokens/supertokens-golang/recipe/thirdpartyemailpassword"
    "github.com/supertokens/supertokens-golang/recipe/thirdpartyemailpassword/tpepmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    countryOptional := true
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            thirdpartyemailpassword.Init(&tpepmodels.TypeInput{
                SignUpFeature: &epmodels.TypeInputSignUp{
                    FormFields: []epmodels.TypeInputFormField{
                        {
                            ID: "name",
                        },
                        {
                            ID: "age",
                        },
                        {
                            ID:       "country",
                            Optional: &countryOptional,
                        },
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import thirdpartyemailpassword, session
from supertokens_python.recipe.emailpassword import InputFormField
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    framework='...', 
    recipe_list=[
        thirdpartyemailpassword.init(
            sign_up_feature=thirdpartyemailpassword.InputSignUpFeature(
                form_fields=[InputFormField(id='name'), InputFormField(id='age'), InputFormField(id='country', optional=True)]
            )
        ),
        session.init()
    ]
)
Step 3: Handle form fields on successful Sign-up#
- NodeJS
- GoLang
- Python
- >= v8.0.0
- < v8.0.0
To handle form fields on the backend you'll have to override the emailPasswordSignUpPOST API when initializing the recipe
import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    supertokens: {
        connectionURI: "...",
    },
    recipeList: [
        ThirdPartyEmailPassword.init({
            override: {
                apis: (originalImplementation) => {
                    return {
                        ...originalImplementation,
                        emailPasswordSignUpPOST: async function (input) {
                            if (originalImplementation.emailPasswordSignUpPOST === undefined) {
                                throw Error("Should never come here");
                            }
                            // First we call the original implementation
                            let response = await originalImplementation.emailPasswordSignUpPOST(input);
                            // If sign up was successful
                            if (response.status === "OK") {
                                // We can get the form fields from the input like this
                                let formFields = input.formFields
                                let user = response.user
                                // some post sign up logic
                            }
                            return response;
                        }
                    }
                }
            }
        }),
        Session.init({ /* ... */ })
    ]
});
To handle form fields on the backend you'll have to override the signInUpPOST API when initializing the recipe
import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    supertokens: {
        connectionURI: "...",
    },
    recipeList: [
        ThirdPartyEmailPassword.init({
            override: {
                apis: (originalImplementation) => {
                    return {
                        ...originalImplementation,
                        signInUpPOST: async function (input) {
                            if (originalImplementation.signInUpPOST === undefined) {
                                throw Error("Should never come here");
                            }
                            // First we call the original implementation of signInUpPOST.
                            let response = await originalImplementation.signInUpPOST(input);
                            // Post sign up response, we check if it was successful
                            if (response.status === "OK") {
                                // Then we check if the user signed up using email / password 
                                if (input.type === "emailpassword") {
                                    // These are the input form fields values that the user used while signing up or in
                                    let formFields = input.formFields;
                                }
                            }
                            return response;
                        }
                    }
                }
            }
        }),
        Session.init({ /* ... */ })
    ]
});
To handle form fields on the backend you'll have to override the EmailPasswordSignUpPOST API when initializing the recipe
import (
    "fmt"
    "github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels"
    "github.com/supertokens/supertokens-golang/recipe/thirdpartyemailpassword"
    "github.com/supertokens/supertokens-golang/recipe/thirdpartyemailpassword/tpepmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            thirdpartyemailpassword.Init(&tpepmodels.TypeInput{
                Override: &tpepmodels.OverrideStruct{
                    APIs: func(originalImplementation tpepmodels.APIInterface) tpepmodels.APIInterface {
                        // First we copy the original implementation
                        originalEmailPasswordSignUpPOST := *originalImplementation.EmailPasswordSignUpPOST
                        (*originalImplementation.EmailPasswordSignUpPOST) = func(formFields []epmodels.TypeFormField, options epmodels.APIOptions, userContext supertokens.UserContext) (tpepmodels.SignUpPOSTResponse, error) {
                            // First we call the original implementation
                            resp, err := originalEmailPasswordSignUpPOST(formFields, options, userContext)
                            if err != nil {
                                return tpepmodels.SignUpPOSTResponse{}, err
                            }
                            // if sign up was successful
                            if resp.OK != nil {
                                // TODO: The input of this function is the formFields array.
                                // You can also retrieve the user object like this:
                                user := resp.OK.User
                                fmt.Println(user)
                            }
                            return resp, err
                        }
                        return originalImplementation
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import thirdpartyemailpassword
from supertokens_python.recipe.thirdpartyemailpassword.interfaces import APIInterface, EmailPasswordAPIOptions, EmailPasswordSignUpPostOkResult
from typing import List, Dict, Any
from supertokens_python.recipe.emailpassword.types import FormField
def override_apis(original_implementation: APIInterface):
    
    original_emailpassword_sign_up_post = original_implementation.emailpassword_sign_up_post
    
    async def emailpassword_sign_up_post(form_fields: List[FormField],
                                         api_options: EmailPasswordAPIOptions, user_context: Dict[str, Any]):
        # First we call the original implementation of sign_up_post
        response = await original_emailpassword_sign_up_post(form_fields, api_options, user_context)
        # Post sign up response, we check if it was successful
        if isinstance(response, EmailPasswordSignUpPostOkResult):
            if response.user is None:
                raise Exception("Should never come here")
            _ = response.user.user_id
            __ = response.user.email
            # TODO: use the input form fields values for custom logic
        return response
    original_implementation.emailpassword_sign_up_post = emailpassword_sign_up_post
    return original_implementation
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    framework='...', 
    recipe_list=[
        thirdpartyemailpassword.init(
            override=thirdpartyemailpassword.InputOverrideConfig(
                apis=override_apis
            )
        )
    ]
)
caution
SuperTokens does not store custom form fields. You need to store them in your db post user sign up.