# Quickstart Guide

Add SuperTokens authentication to your frontend and backend, then prepare the integration for production.

## [Overview](/content/docs/quickstart?q=BWvr89TAB\#overview/index.html)

Ask an agent to integrate SuperTokens into an existing application.

Copy promptCopied

Inspect this repository and integrate SuperTokens into the existing application. First discover the frontend stack and backend stack, including languages, frameworks, package managers, routers, SDK versions, existing authentication code, and environment configuration. If the frontend or backend stack cannot be determined reliably, ask the user to provide it before making changes. Also ask which authentication methods and UI approach they need if those choices cannot be inferred. Use the current SuperTokens documentation and SDK APIs, preserve the project’s conventions, and do not commit secrets. Configure the frontend, backend, sessions, routes, middleware, cookies, CORS, and environment variables as required. Run the relevant typechecks, tests, and build, then summarize changed files, required environment variables, and validation results.

This guide walks through adding Email/Password authentication with either the SuperTokens prebuilt UI or your own custom UI. Configure the frontend first, then connect your backend and prepare the integration for production.

## [Steps](/content/docs/quickstart?q=BWvr89TAB\#steps/index.html)

### [1\. Integrate the frontend SDK](/content/docs/quickstart?q=BWvr89TAB\#1-integrate-the-frontend-sdk/index.html)

Start the setup by configuring your frontend application to use **SuperTokens** for authentication.

This guide uses the **SuperTokens pre-built UI** components.
If you want to create your own interface please check the **Custom UI** tutorial.

UI type

Pre-built UIDrop-in components that handle the flows for you.Custom UIBuild your own UI and call the SDK directly.

#### [1.1 Install the SDK](/content/docs/quickstart?q=BWvr89TAB\#prebuilt-ui-install-sdk/index.html)

Run the following command in your terminal to install the package.

ReactjsAngularVue

Frontend framework

React▼

Package manager

npm▼

```
  npm i -s supertokens-auth-react

```

```
yarn add supertokens-auth-react supertokens-web-js

```

```
pnpm add supertokens-auth-react supertokens-web-js

```

```
bun add supertokens-auth-react supertokens-web-js

```

```
npm i -s supertokens-web-js

```

```
yarn add supertokens-web-js

```

```
pnpm add supertokens-web-js

```

```
bun add supertokens-web-js

```

```
npm i -s supertokens-web-js

```

```
yarn add supertokens-web-js

```

```
pnpm add supertokens-web-js

```

```
bun add supertokens-web-js

```

#### [1.2 Initialize the SDK](/content/docs/quickstart?q=BWvr89TAB\#12-initialize-the-sdk/index.html)

Reactjs

In your main application file call the `SuperTokens.init` function to initialize the SDK.
The `init` call includes the [main configuration details](/content/docs/references/frontend-sdks/reference#sdk-configuration/index.html), as well as the **recipes** that you use in your setup.
After that you have to wrap the application with the `SuperTokensWrapper` component.
This provides authentication context for the rest of the UI tree.

Angular

Before we initialize the `supertokens-web-js` SDK let’s see how we use it in our Angular app.

**Architecture**

- The `supertokens-web-js` SDK is responsible for session management and providing helper functions to check if a session exists, or validate the access token claims on the frontend (for example, to check for user roles before showing some UI). We initialise this SDK on the root of your Angular app, so that all pages in your app can use it.
- You have to create a `/auth*` route in the Angular app which renders our pre-built UI. which also needs to be initialised, but only on that route.

##### [Creating the `/auth` route](/content/docs/quickstart?q=BWvr89TAB\#prebuilt-angular-auth-route/index.html)

- Use the Angular CLI to generate a new route

Vue

Before we initialize the `supertokens-web-js` SDK let’s see how we use it in our Vue app

**Architecture**

- The `supertokens-web-js` SDK is responsible for session management and providing helper functions to check if a session exists, or validate the access token claims on the frontend (for example, to check for user roles before showing some UI). We initialise this SDK on the root of your Vue app, so that all pages in your app can use it.
- We create a `/auth*` route in the Vue app which renders our pre-built UI which also needs to be initialised, but only on that route.

**Creating the `/auth` route**

- Create a new file `AuthView.vue`, this Vue component is used to render the auth component:

ReactjsAngularVue

Frontend framework

React▼

```
import React from "react";

import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import EmailPassword from "supertokens-auth-react/recipe/emailpassword";
import Session from "supertokens-auth-react/recipe/session";

SuperTokens.init({
  appInfo: {
    // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
    apiBasePath: "/auth",
    websiteBasePath: "/auth",
  },
  recipeList: [EmailPassword.init(), Session.init()],
});

/* Your App */
class App extends React.Component {
  render() {
    return <SuperTokensWrapper>{/*Your app components*/}</SuperTokensWrapper>;
  }
}

```

```
      ng generate module auth --route auth --module app.module

```

```
  <script lang="ts">
      import { defineComponent, onMounted, onUnmounted } from 'vue';
      export default defineComponent({
          setup() {
              const loadScript = (src: string) => {
                  const script = document.createElement('script');
                  script.type = 'text/javascript';
                  script.src = src;
                  script.id = 'supertokens-script';
                  script.onload = () => {
                      supertokensUIInit("supertokensui", {
                          appInfo: {
                              appName: "<YOUR_APP_NAME>",
                              apiDomain: "<YOUR_API_DOMAIN>",
                              websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
                              apiBasePath: "/auth",
                              websiteBasePath: "/auth"
                          },
                          recipeList: [\
                              supertokensUIEmailPassword.init(),\
                              supertokensUISession.init(),\
                          ],
                      });
                  };
                  document.body.appendChild(script);
              };

onMounted(() => {
                  loadScript('https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@v0.48.0/build/static/js/main.81589a39.js');
              });

onUnmounted(() => {
                  const script = document.getElementById('supertokens-script');
                  if (script) {
                      script.remove();
                  }
              });
          },
      });
  </script>

<template>
      <div id="supertokensui" />
  </template>

```

Reactjs

Angular

- Add the following code to your `auth` angular component

Vue

- In the `loadScript` function, we provide the SuperTokens config for the UI. We add the `emailpassword` and session recipes.

- Initialize the `supertokens-web-js` SDK in your Vue app’s `main.ts` file. This provides session management across your entire application.

AngularVue

```
    import { Component, OnDestroy, AfterViewInit, Renderer2, Inject } from "@angular/core";
    import { DOCUMENT } from "@angular/common";

@Component({
      selector: "app-auth",
      template: '<div id="supertokensui"></div>',
    })
    export class AuthComponent implements OnDestroy, AfterViewInit {
      constructor(
        private renderer: Renderer2,
        @Inject(DOCUMENT) private document: Document,
      ) {}

ngAfterViewInit() {
        this.loadScript("https://cdn.jsdelivr.net/gh/supertokens/prebuiltui@v0.48.0/build/static/js/main.81589a39.js");
      }

ngOnDestroy() {
        // Remove the script when the component is destroyed
        const script = this.document.getElementById("supertokens-script");
        if (script) {
          script.remove();
        }
      }

private loadScript(src: string) {
        const script = this.renderer.createElement("script");
        script.type = "text/javascript";
        script.src = src;
        script.id = "supertokens-script";
        script.onload = () => {
          supertokensUIInit("supertokensui", {
            appInfo: {
              appName: "<YOUR_APP_NAME>",
              apiDomain: "<YOUR_API_DOMAIN>",
              websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
              apiBasePath: "/auth",
              websiteBasePath: "/auth",
            },
            recipeList: [supertokensUIEmailPassword.init(), supertokensUISession.init()],
          });
        };
        this.renderer.appendChild(this.document.body, script);
      }
    }

```

```
    import { createApp } from "vue";
    import SuperTokens from "supertokens-web-js";
    import Session from "supertokens-web-js/recipe/session";
    import App from "./App.vue";
    import router from "./router";

SuperTokens.init({
      appInfo: {
        appName: "<YOUR_APP_NAME>",
        apiDomain: "<YOUR_API_DOMAIN>",
        apiBasePath: "/auth",
      },
      recipeList: [Session.init()],
    });

const app = createApp(App);

app.use(router);

app.mount("#app");

```

Reactjs

Angular

- In the `loadScript` function, we provide the SuperTokens config for the UI. We add the `emailpassword` and session recipes.

- Initialize the `supertokens-web-js` SDK in your angular app’s root component. This provides session management across your entire application.

Vue

Angular

```
import SuperTokens from "supertokens-web-js";
import Session from "supertokens-web-js/recipe/session";

SuperTokens.init({
  appInfo: {
    appName: "<YOUR_APP_NAME>",
    apiDomain: "<YOUR_API_DOMAIN>",
    apiBasePath: "/auth",
  },
  recipeList: [Session.init()],
});

```

#### [1.3 Configure routing](/content/docs/quickstart?q=BWvr89TAB\#13-configure-routing/index.html)

Reactjs

In order for the **pre-built UI** to be rendered inside your application, you have to specify which routes show the authentication components.
The **React SDK** uses [**React Router**](https://reactrouter.com/en/main) under the hood to achieve this.
Based on whether you already use this package or not in your project, there are two different ways of configuring the routes.

With React Router

Call the `getSuperTokensRoutesForReactRouterDom` method from within any `react-router-dom``Routes` component.

Without React Router

Add the route handling shown below to your root-level `render` function.

Angular

Update your angular router so that all auth related requests load the `auth` component

Vue

Update your Vue router so that all auth related requests load the `AuthView` component

ReactjsAngularVue

Frontend framework

React▼

Do you use react-router-dom?

With React Router▼

```
import React from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";

import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui";
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";
import * as reactRouterDom from "react-router-dom";

class App extends React.Component {
  render() {
    return (
      <SuperTokensWrapper>
        <BrowserRouter>
          <Routes>
            {/*This renders the login UI on the /auth route*/}
            {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUI])}
            {/*Your app routes*/}
          </Routes>
        </BrowserRouter>
      </SuperTokensWrapper>
    );
  }
}

```

```
import React from "react";
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui";

class App extends React.Component {
  render() {
    if (canHandleRoute([EmailPasswordPreBuiltUI])) {
      // This renders the login UI on the /auth route
      return getRoutingComponent([EmailPasswordPreBuiltUI]);
    }

return <SuperTokensWrapper>{/*Your app*/}</SuperTokensWrapper>;
  }
}

```

```
    import { NgModule } from "@angular/core";
    import { RouterModule, Routes } from "@angular/router";

const routes: Routes = [\
      {\
        path: "auth",\
        loadChildren: () => import("./auth/auth.module").then((m) => m.AuthModule),\
      },\
\
      {\
        path: "**",\
        loadChildren: () => import("./home/home.module").then((m) => m.HomeModule),\
      },\
    ];

@NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}

```

```
    import { createRouter, createWebHistory } from "vue-router";
    import HomeView from "../views/HomeView.vue";
    import AuthView from "../views/AuthView.vue";

const router = createRouter({
      history: createWebHistory(import.meta.env.BASE_URL),
      routes: [\
        {\
          path: "/",\
          name: "home",\
          component: HomeView,\
        },\
        {\
          path: "/auth/:pathMatch(.*)*",\
          name: "auth",\
          component: AuthView,\
        },\
      ],
    });

export default router;

```

Reactjs

With React Router

Without React Router

Angular

Vue

Reactjs

```
import React from "react";

import { BrowserRouter, useRoutes } from "react-router-dom";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui";
import * as reactRouterDom from "react-router-dom";

function AppRoutes() {
  const authRoutes = getSuperTokensRoutesForReactRouterDom(reactRouterDom, [\
    /* Add your UI recipes here e.g. EmailPasswordPrebuiltUI, PasswordlessPrebuiltUI, ThirdPartyPrebuiltUI */\
  ]);

const routes = useRoutes([\
    ...authRoutes.map((route) => route.props),\
    // Include the rest of your app routes\
  ]);

return routes;
}

function App() {
  return (
    <SuperTokensWrapper>
      <BrowserRouter>
        <AppRoutes />
      </BrowserRouter>
    </SuperTokensWrapper>
  );
}

```

#### [1.4 Handle session tokens](/content/docs/quickstart?q=BWvr89TAB\#14-handle-session-tokens/index.html)

This part is handled automatically by the **Frontend SDK**.
You don’t need to do anything.
The step serves more as a way for us to tell you how is this handled under the hood.

After you call the `init` function, the **SDK** adds interceptors to both `fetch` and `XHR`, XMLHTTPRequest. The latter is used by the `axios` library.
The interceptors save the session tokens that are generated from the authentication flow.
Those tokens are then added to requests initialized by your frontend app which target the backend API.
By default, the tokens are stored through session cookies but you can also switch to [header based authentication](/content/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication/index.html).

#### [1.5 Secure application routes](/content/docs/quickstart?q=BWvr89TAB\#15-secure-application-routes/index.html)

In order to prevent unauthorized access to certain parts of your frontend application you can use our utilities.
Follow the code samples below to understand how to do this.

Reactjs

You can wrap your components with the `<SessionAuth>` react component. This ensures that your component renders only if the user is logged in. If they are not logged in, the user is redirected to the login page.

Angular

You can use the `doesSessionExist` function to check if a session exists in all your routes.

Vue

You can use the `doesSessionExist` function to check if a session exists in all your routes.

ReactjsAngularVue

Frontend framework

React▼

```
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { SessionAuth } from "supertokens-auth-react/recipe/session";
import MyDashboardComponent from "./dashboard";

class App extends React.Component {
  render() {
    return (
      <BrowserRouter>
        <Routes>
          <Route
            path="/dashboard"
            element={
              <SessionAuth>
                {/*Components that require to be protected by authentication*/}
                <MyDashboardComponent />
              </SessionAuth>
            }
          />
        </Routes>
      </BrowserRouter>
    );
  }
}

```

```
import Session from "supertokens-web-js/recipe/session";

async function doesSessionExist() {
  if (await Session.doesSessionExist()) {
    // user is logged in
  } else {
    // user has not logged in yet
  }
}

```

```
import Session from "supertokens-web-js/recipe/session";

async function doesSessionExist() {
  if (await Session.doesSessionExist()) {
    // user is logged in
  } else {
    // user has not logged in yet
  }
}

```

#### [1.1 Install the SDK](/content/docs/quickstart?q=BWvr89TAB\#custom-ui-install-sdk/index.html)

Use the following command to install the required package.

Web

npm

Mobile

ReactNative

Android

Add to your `settings.gradle`:

iOS

##### [Using CocoaPods](/content/docs/quickstart?q=BWvr89TAB\#custom-ui-ios-cocoapods/index.html)

Add the CocoaPods dependency to your `Podfile`

Flutter

Add the dependency to your pubspec.yaml

WebMobile

Platform

Web▼

```
npm i -s supertokens-web-js

```

```
npm i -s supertokens-react-native@5.1.5 @react-native-async-storage/async-storage@2.2.0

```

```
dependencyResolutionManagement {
    ...
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

```

```
pod 'SuperTokensIOS', '0.4.2'

```

```
supertokens_flutter: 0.6.5

```

Web

Mobile

ReactNative

Android

Add the following to you app level’s `build.gradle`:

iOS

##### [Using Swift Package Manager](/content/docs/quickstart?q=BWvr89TAB\#using-swift-package-manager/index.html)

Follow the [official documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) to learn how to use Swift Package Manager to add dependencies to your project.

When adding the dependency, select version `0.4.2` after you enter the SuperTokens iOS repository URL:

Flutter

You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-flutter/releases) (ignore the `v` prefix in the releases).

Mobile

```
implementation 'com.github.supertokens:supertokens-android:0.5.3'

```

```
https://github.com/supertokens/supertokens-ios

```

Web

Mobile

ReactNative

Android

You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-android/releases) (ignore the `v` prefix in the releases).

iOS

Flutter

#### [1.2 Initialize SuperTokens](/content/docs/quickstart?q=BWvr89TAB\#12-initialize-supertokens/index.html)

Call the SDK init function at the start of your application.
The invocation includes the [main configuration details](/content/docs/references/frontend-sdks/reference#sdk-configuration/index.html), as well as the **recipes** that you use in your setup.

Web

Mobile

ReactNative

Android

Add the `SuperTokens.init` function call at the start of your application.

iOS

Flutter

WebMobile

Platform

Web▼

```
import SuperTokens from "supertokens-web-js";
import Session from "supertokens-web-js/recipe/session";
import EmailPassword from "supertokens-web-js/recipe/emailpassword";

SuperTokens.init({
  appInfo: {
    apiDomain: "<YOUR_API_DOMAIN>",
    apiBasePath: "/auth",
    appName: "...",
  },
  recipeList: [Session.init(), EmailPassword.init()],
});

```

```
import SuperTokens from "supertokens-react-native";

SuperTokens.init({
  apiDomain: "<YOUR_API_DOMAIN>",
  apiBasePath: "/auth",
});

```

```
import android.app.Application
import com.supertokens.session.SuperTokens

class MainApplication: Application() {
    override fun onCreate() {
        super.onCreate()

SuperTokens.Builder(this, "<YOUR_API_DOMAIN>")
            .apiBasePath("/auth")
            .build()
    }
}

```

```
import UIKit
import SuperTokensIOS

fileprivate class ApplicationDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        do {
            try SuperTokens.initialize(
                apiDomain: "<YOUR_API_DOMAIN>",
                apiBasePath: "/auth"
            )
        } catch SuperTokensError.initError(let message) {
            // TODO: Handle initialization error
        } catch {
            // Some other error
        }

return true
    }

}

```

```
import 'package:supertokens_flutter/supertokens.dart';

void main() {
    SuperTokens.init(
        apiDomain: "<YOUR_API_DOMAIN>",
        apiBasePath: "/auth",
    );
}

```

#### [1.3 Add the login UI](/content/docs/quickstart?q=BWvr89TAB\#13-add-the-login-ui/index.html)

The **Email/Password** flow involves two types of user interfaces.
One for registering and creating new users, the _Sign Up Form_.
And one for the actual authentication attempt, the _Sign In Form_.
If you are provisioning users from a different method you can skip over adding the sign up form.

##### [1.3.1 Add the sign-up form](/content/docs/quickstart?q=BWvr89TAB\#131-add-the-sign-up-form/index.html)

Web

For the **Sign Up** flow you have to first add the UI elements which render your form.
After that, call the following function when the user submits the form that you have previously created.

Mobile

For the **Sign Up** flow you have to first add the UI elements which render your form.
After that, call the following API when the user submits the form that you have previously created.

WebMobile

Platform

Web▼

```
import { signUp } from "supertokens-web-js/recipe/emailpassword";

async function signUpClicked(email: string, password: string) {
  try {
    let response = await signUp({
      formFields: [\
        {\
          id: "email",\
          value: email,\
        },\
        {\
          id: "password",\
          value: password,\
        },\
      ],
    });

if (response.status === "FIELD_ERROR") {
      // one of the input formFields failed validation
      response.formFields.forEach((formField) => {
        if (formField.id === "email") {
          // Email validation failed (for example incorrect email syntax),
          // or the email is not unique.
          window.alert(formField.error);
        } else if (formField.id === "password") {
          // Password validation failed.
          // Maybe it didn't match the password strength
          window.alert(formField.error);
        }
      });
    } else if (response.status === "SIGN_UP_NOT_ALLOWED") {
      // the reason string is a user friendly message
      // about what went wrong. It can also contain a support code which users
      // can tell you so you know why their sign up was not allowed.
      window.alert(response.reason);
    } else {
      // sign up successful. The session tokens are automatically handled by
      // the frontend SDK.
      window.location.href = "/homepage";
    }
  } catch (err: any) {
    if (err.isSuperTokensGeneralError === true) {
      // this may be a custom error message sent from the API by you.
      window.alert(err.message);
    } else {
      window.alert("Oops! Something went wrong.");
    }
  }
}

```

```
curl --location --request POST '<YOUR_API_DOMAIN>/auth/signup' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
    "formFields": [{\
        "id": "email",\
        "value": "john@example.com"\
    }, {\
        "id": "password",\
        "value": "somePassword123"\
    }]
}'

```

Web

Mobile

The response body from the API call has a `status` property in it:

- `status: "OK"`: User creation was successful. The response also contains more information about the user, for example their user ID.

- `status: "FIELD_ERROR"`: One of the form field inputs failed validation. The response body contains information about which form field input based on the `id`:

- The email could fail validation if it’s syntactically not an email, of it it’s not unique.
  - The password could fail validation if it’s not string enough (as defined by the backend password validator).

Either way, you want to show the user an error next to the input form field.

- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend.

- `status: "SIGN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that’s in the response body contains a support code using which you can see why the sign up was not allowed.

The `formFields` input is a key-value array. You must provide it an `email` and a `password` value at a minimum. If you want to provide additional items, for example the user’s name or age, you can append it to the array like so:

```
{
  "formFields": [\
    {\
      "id": "email",\
      "value": "john@example.com"\
    },\
    {\
      "id": "password",\
      "value": "somePassword123"\
    },\
    {\
      "id": "name",\
      "value": "John Doe"\
    }\
  ]
}

```

On the backend, the `formFields` array is available to you for consumption.

On success, the backend sends back session tokens as part of the response headers which are automatically handled by our frontend SDK for you.

###### [How to check if an email is unique](/content/docs/quickstart?q=BWvr89TAB\#how-to-check-if-an-email-is-unique/index.html)

As a part of the sign up form, you may want to explicitly check that the entered email is unique.
Whilst this is already done via the sign up API call, it may be a better UX to warn the user about a non unique email right after they finish typing it.

WebMobile

Platform

Web▼

```
import { doesEmailExist } from "supertokens-web-js/recipe/emailpassword";

async function checkEmail(email: string) {
  try {
    let response = await doesEmailExist({
      email,
    });

if (response.doesExist) {
      window.alert("Email already exists. Please sign in instead");
    }
  } catch (err: any) {
    if (err.isSuperTokensGeneralError === true) {
      // this may be a custom error message sent from the API by you.
      window.alert(err.message);
    } else {
      window.alert("Oops! Something went wrong.");
    }
  }
}

```

```
curl --location --request GET '<YOUR_API_DOMAIN>/auth/emailpassword/email/exists?email=john@example.com'

```

Web

Mobile

The response body from the API call has a `status` property in it:

- `status: "OK"`: The response also contains a `exists` boolean which is `true` if the input email already belongs to an email password user.
- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend.

##### [1.3.2 Add the sign-in form](/content/docs/quickstart?q=BWvr89TAB\#132-add-the-sign-in-form/index.html)

Web

For the **Sign In** flow you have to first add the UI elements which render your form.
After that, call the following function when the user submits the form that you have previously created.

Mobile

For the **Sign In** flow you have to first add the UI elements which render your form.
After that, call the following API when the user submits the form that you have previously created.

WebMobile

Platform

Web▼

```
import { signIn } from "supertokens-web-js/recipe/emailpassword";

async function signInClicked(email: string, password: string) {
  try {
    let response = await signIn({
      formFields: [\
        {\
          id: "email",\
          value: email,\
        },\
        {\
          id: "password",\
          value: password,\
        },\
      ],
    });

if (response.status === "FIELD_ERROR") {
      response.formFields.forEach((formField) => {
        if (formField.id === "email") {
          // Email validation failed (for example incorrect email syntax).
          window.alert(formField.error);
        }
      });
    } else if (response.status === "WRONG_CREDENTIALS_ERROR") {
      window.alert("Email password combination is incorrect.");
    } else if (response.status === "SIGN_IN_NOT_ALLOWED") {
      // the reason string is a user friendly message
      // about what went wrong. It can also contain a support code which users
      // can tell you so you know why their sign in was not allowed.
      window.alert(response.reason);
    } else {
      // sign in successful. The session tokens are automatically handled by
      // the frontend SDK.
      window.location.href = "/homepage";
    }
  } catch (err: any) {
    if (err.isSuperTokensGeneralError === true) {
      // this may be a custom error message sent from the API by you.
      window.alert(err.message);
    } else {
      window.alert("Oops! Something went wrong.");
    }
  }
}

```

```
curl --location --request POST '<YOUR_API_DOMAIN>/auth/signin' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
    "formFields": [{\
        "id": "email",\
        "value": "john@example.com"\
    }, {\
        "id": "password",\
        "value": "somePassword123"\
    }]
}'

```

Web

Mobile

The response body from the API call has a `status` property in it:

- `status: "OK"`: User sign in was successful. The response also contains more information about the user, for example their user ID.
- `status: "WRONG_CREDENTIALS_ERROR"`: The input email and password combination is incorrect.
- `status: "FIELD_ERROR"`: This indicates that the input email did not pass the backend validation - probably because it’s syntactically not an email. You want to show the user an error next to the email input form field.
- `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend.
- `status: "SIGN_IN_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that’s in the response body contains a support code using which you can see why the sign in was not allowed.

On success, the backend sends back session tokens as part of the response headers which are automatically handled by our frontend SDK for you.

#### [1.4 Handle session tokens](/content/docs/quickstart?q=BWvr89TAB\#14-handle-session-tokens-1/index.html)

You can use sessions with SuperTokens in two modes:

- Using `httpOnly` cookies
- Authorization bearer token.

Our frontend SDK uses `httpOnly` cookie based session for websites by default as it secures against tokens theft via XSS attacks.
For other platforms, like mobile apps, we use a bearer token in the `Authorization` header by default.

##### [With the Frontend SDK](/content/docs/quickstart?q=BWvr89TAB\#with-the-frontend-sdk/index.html)

Web

Our frontend SDK handles everything for you. You only need to make sure that you have called `supertokens.init` before making any network requests.

Our SDK adds interceptors to `fetch` and `XHR` (used by `axios`) to save and add session tokens from and to the request.

By default, our web SDKs use cookies to provide credentials.

Mobile

ReactNative

Our frontend SDK handles everything for you. You only need to make sure that you have added our network interceptors as shown below

###### [Axios](/content/docs/quickstart?q=BWvr89TAB\#axios/index.html)

###### [Using a custom Axios instance](/content/docs/quickstart?q=BWvr89TAB\#using-a-custom-axios-instance/index.html)

Android

###### [HttpURLConnection](/content/docs/quickstart?q=BWvr89TAB\#httpurlconnection/index.html)

iOS

###### [`URLSession`](/content/docs/quickstart?q=BWvr89TAB\#urlsession/index.html)

###### [Using `URLSession.shared`](/content/docs/quickstart?q=BWvr89TAB\#using-urlsessionshared/index.html)

Flutter

###### [`http`](/content/docs/quickstart?q=BWvr89TAB\#http/index.html)

You can make requests as you normally would with `http`, the only difference is that you import the client from the SuperTokens package instead.

Mobile

Mobile framework

ReactNative▼

```
import axios from "axios";
import SuperTokens from "supertokens-react-native";

let axiosInstance = axios.create({
  /*...*/
});
SuperTokens.addAxiosInterceptors(axiosInstance);

async function callAPI() {
  // use axios as you normally do
  let response = await axiosInstance.get("https://yourapi.com");
}

```

```
import android.app.Application
import com.supertokens.session.SuperTokens
import com.supertokens.session.SuperTokensHttpURLConnection
import com.supertokens.session.SuperTokensPersistentCookieStore
import java.net.URL
import java.net.HttpURLConnection

class MainApplication: Application() {
    override fun onCreate() {
        super.onCreate()
        // TODO: Make sure to call SuperTokens.init
    }

fun makeRequest() {
        val url = URL("<API_URL>")
        val connection = SuperTokensHttpURLConnection.newRequest(url, object: SuperTokensHttpURLConnection.PreConnectCallback {
            override fun doAction(con: HttpURLConnection?) {
                // TODO: Use `con` to set request method, headers etc
            }
        })

// Handle response using connection object, for example:
        if (connection.responseCode == 200) {
            // TODO: implement
        }
    }
}

```

```
import Foundation
import SuperTokensIOS

fileprivate class NetworkManager {
    func setupSuperTokensInterceptor() {
        URLProtocol.registerClass(SuperTokensURLProtocol.self)
    }
}

```

```
import 'package:supertokens_flutter/http.dart' as http;
// SuperTokens wraps the package:http API.

Future<void> makeRequest() async {
    Uri uri = Uri.parse("http://localhost:3001/api");
    var response = await http.get(uri);
    // handle response
}

```

Web

Mobile

ReactNative

###### [Using the global Axios instance](/content/docs/quickstart?q=BWvr89TAB\#using-the-global-axios-instance/index.html)

Android

###### [OkHttp or Retrofit](/content/docs/quickstart?q=BWvr89TAB\#okhttp-or-retrofit/index.html)

iOS

###### [Using a custom `URLSession` instance](/content/docs/quickstart?q=BWvr89TAB\#using-a-custom-urlsession-instance/index.html)

Flutter

###### [Using a custom HTTP client](/content/docs/quickstart?q=BWvr89TAB\#using-a-custom-http-client/index.html)

If you use a custom HTTP client and want to use SuperTokens, you can simply provide the SDK with your client. All requests continue to use your client along with the session logic that SuperTokens provides.

Mobile

```
import axios from "axios";
import SuperTokens from "supertokens-react-native";
SuperTokens.addAxiosInterceptors(axios);

async function callAPI() {
  // use axios as you normally do
  let response = await axios.get("https://yourapi.com");
}

```

```
import android.content.Context
import com.supertokens.session.SuperTokens
import com.supertokens.session.SuperTokensInterceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit

class NetworkManager {
    fun getClient(context: Context): OkHttpClient {
        val clientBuilder = OkHttpClient.Builder()
        clientBuilder.addInterceptor(SuperTokensInterceptor())
        // TODO: Make sure to call SuperTokens.init

val client = clientBuilder.build()

// REQUIRED FOR RETROFIT ONLY
        val instance = Retrofit.Builder()
            .baseUrl("<YOUR_BASE_URL>")
            .client(client)
            .build()

return client
    }

fun makeRequest(context: Context) {
        val client = getClient(context)
        // Use client to make requests normally
    }
}

```

```
import Foundation
import SuperTokensIOS

fileprivate class NetworkManager {
    func setupSuperTokensInterceptor() {
        let configuration = URLSessionConfiguration.default
        configuration.protocolClasses = [SuperTokensURLProtocol.self]
        let session = URLSession(configuration: configuration)

// Use session when making network requests
    }
}

```

```
import 'package:http/http.dart' as base_http;
import 'package:supertokens_flutter/http.dart' as supertokens_http;

Future<void> makeRequest() async {
    Uri uri = Uri.parse("http://localhost:3001/api");

var customClient = base_http.Client();
    var httpClient = supertokens_http.Client(client: customClient);

var response = await httpClient.get(uri);
    // handle response
}

```

Web

Mobile

ReactNative

###### [Fetch](/content/docs/quickstart?q=BWvr89TAB\#fetch/index.html)

Android

iOS

###### [Alamofire](/content/docs/quickstart?q=BWvr89TAB\#alamofire/index.html)

Flutter

###### [Dio](/content/docs/quickstart?q=BWvr89TAB\#dio/index.html)

###### [Add the SuperTokens interceptor](/content/docs/quickstart?q=BWvr89TAB\#add-the-supertokens-interceptor/index.html)

Use the extension method provided by the SuperTokens SDK to enable interception on your `Dio` client. This allows the SuperTokens SDK to handle session tokens for you.

Mobile

```
import Foundation
import SuperTokensIOS
import Alamofire

fileprivate class NetworkManager {
    func setupSuperTokensInterceptor() {
        let configuration = URLSessionConfiguration.af.default
        configuration.protocolClasses = [SuperTokensURLProtocol.self] + (configuration.protocolClasses ?? [])
        let session = Session(configuration: configuration)

// Use session when making network requests
    }
}

```

```
import 'package:supertokens_flutter/dio.dart';
import 'package:dio/dio.dart';

void setup() {
  Dio dio = Dio();  // Create a Dio instance.
  dio.addSupertokensInterceptor();
}

```

Web

Mobile

ReactNative

Android

iOS

Flutter

###### [Making network requests](/content/docs/quickstart?q=BWvr89TAB\#making-network-requests/index.html)

You can make requests as you normally would with `dio`.

Mobile

```
import 'package:supertokens_flutter/dio.dart';
import 'package:dio/dio.dart';

void setup() {
    Dio dio = Dio(
        // Provide your config here
    );
    dio.addSupertokensInterceptor();

var response = dio.get("http://localhost:3001/api");
    // handle response
}

```

Web

Mobile

ReactNative

Android

iOS

Flutter

##### [Without the Frontend SDK](/content/docs/quickstart?q=BWvr89TAB\#without-the-frontend-sdk/index.html)

In this case, you need to manually handle the tokens and session refreshing, and decide if you are going to use header or cookie-based sessions.

For browsers, we recommend cookies, while for mobile apps (or if you don’t want to use the built-in cookie manager) you should use header-based sessions.

CookieHeader (Authorization Bearer)

###### [During the Login Action](/content/docs/quickstart?q=BWvr89TAB\#during-the-login-action/index.html)

You should attach the `st-auth-mode` header to calls to the login API, but this header is safe to attach to all requests. In this case it should be set to “cookie”.

The login API returns the following headers:

- `Set-Cookie`: This contains the `sAccessToken`, `sRefreshToken` cookies which are `httpOnly` and are automatically managed by the browser. For mobile apps, you need to setup cookie handling yourself, use our SDK or use a header based authentication mode.

- `front-token` header: This contains information about the access token:

- The userID
  - The expiry time of the access token
  - The payload added by you in the access token.

Here is the structure of the token:

```
let frontTokenFromRequestHeader = "...";
let frontTokenDecoded = JSON.parse(decodeURIComponent(escape(atob(frontTokenFromRequestHeader))));
console.log(frontTokenDecoded);
/*
{
    ate: 1665226412455, // time in milliseconds for when the access token expires, and then a refresh is required
    uid: "....", // user ID
    up: {
        sub: "..",
        iat: ..,
        ... // other access token payload
    }
}

*/

```

This token is mainly used for cookie-based authentication because you don’t have access to the actual access token on the frontend. You may still want to read its payload, for example to adjust the UI based on the user’s role. The token is not signed and must not be used for authorization. If you cache it, treat its contents as untrusted and clear it when the session ends.

- `anti-csrf` header (optional): By default it’s not required, so it’s not sent. But if this is sent, you should save this token as well for use when making requests.

###### [When You Make Network Requests to Protected APIs](/content/docs/quickstart?q=BWvr89TAB\#when-you-make-network-requests-to-protected-apis/index.html)

The `sAccessToken` gets attached to the request automatically by the browser. Other than that, you need to add the following headers to the request:

- `rid: "anti-csrf"` \- this prevents against anti-CSRF requests. If your `apiDomain` and `websiteDomain` values are exactly the same, then this is not necessary.
- `anti-csrf` header (optional): If this was provided to you during login, then you need to add that token as the value of this header.
- For cross-origin browser requests, set the Fetch `credentials` request option to `"include"` (or the equivalent option in your HTTP library). `credentials` is not an HTTP header and does not accept `true` in Fetch.

An API call can potentially update the `sAccessToken` and `front-token` tokens, for example if you call the `mergeIntoAccessTokenPayload` function on the `session` object on the backend. This kind of update is reflected in the response headers for your API calls. The headers contain new values for:

- `sAccessToken`: This is as a new `Set-Cookie` header and is managed by the browser automatically.
- `front-token`: This should be read and saved by you in the same way as it’s being done during login.

###### [Handling session refreshing](/content/docs/quickstart?q=BWvr89TAB\#handling-session-refreshing/index.html)

If a protected API returns `401`, attempt to refresh the session once before retrying the request. A `401` can have causes other than access-token expiry, so do not retry indefinitely.

You can call the refresh API as follows:

```
curl --location --request POST '<YOUR_API_DOMAIN>/auth/session/refresh' \
--header 'Cookie: sRefreshToken=...'

```

The result of a session refresh is either:

- Status code `200`: This implies a successful refresh. The set of tokens returned here is the same as when the user logs in, so you can handle them in the same way.
- Status code `401`: This means that the refresh token is invalid, or has been revoked. You must ask the user to login again. Remember to clear the `front-token` that you saved on the frontend earlier.

###### [During the Login Action](/content/docs/quickstart?q=BWvr89TAB\#during-the-login-action-1/index.html)

You should attach the `st-auth-mode` header to calls to the login API, but this header is safe to attach to all requests. In this case it should be set to “header”.

The login API returns the following headers:

- `st-access-token`: This contains the current access token associated with the session.
- `st-refresh-token`: This contains the current refresh token associated with the session.

Do not persist these tokens in browser `localStorage`, because injected scripts can read them. Prefer the Web SDK’s cookie-based mode for browsers. Native applications should use platform-provided secure storage. If you manually use header-based authentication in a browser, keep tokens in memory and account for the session ending when the page reloads.

###### [When You Make Network Requests to Protected APIs](/content/docs/quickstart?q=BWvr89TAB\#when-you-make-network-requests-to-protected-apis-1/index.html)

You need to add the following headers to request:

- `authorization: Bearer {access-token}`
- Header-based requests do not require the Fetch API’s `credentials` option unless the request also relies on cookies or HTTP authentication.

An API call can potentially update the `access-token`, for example if you call the `mergeIntoAccessTokenPayload` function on the `session` object on the backend. This kind of update is reflected in the response headers for your API calls. The headers contain new values for `st-access-token`

These should be read and saved by you in the same way as it’s being done during login.

###### [Handling session refreshing](/content/docs/quickstart?q=BWvr89TAB\#handling-session-refreshing-1/index.html)

You can call the refresh API as follows:

```
curl --location --request POST '<YOUR_API_DOMAIN>/auth/session/refresh' \
--header 'authorization: Bearer {refresh-token}'

```

The result of a session refresh is either:

- Status code `200`: This implies a successful refresh. The set of tokens returned here is the same as when the user logs in, so you can handle them in the same way.
- Status code `401`: This means that the refresh token is invalid, or has been revoked. You must ask the user to login again. Remember to clear the `st-refresh-token` and `st-access-token` that you saved on the frontend earlier.

#### [1.5 Protect frontend routes](/content/docs/quickstart?q=BWvr89TAB\#15-protect-frontend-routes/index.html)

You can use the `doesSessionExist` function to check if a session exists.

WebMobile

Platform

Web▼

```
import Session from "supertokens-web-js/recipe/session";

async function doesSessionExist() {
  if (await Session.doesSessionExist()) {
    // user is logged in
  } else {
    // user has not logged in yet
  }
}

```

```
import SuperTokens from "supertokens-react-native";

async function doesSessionExist() {
  if (await SuperTokens.doesSessionExist()) {
    // user is logged in
  } else {
    // user has not logged in yet
  }
}

```

```
import android.app.Application
import com.supertokens.session.SuperTokens

class MainApplication: Application() {
    fun doesSessionExist() {
        if (SuperTokens.doesSessionExist(this.applicationContext)) {
            // user is logged in
        } else {
            // user has not logged in yet
        }
    }
}

```

```
import UIKit
import SuperTokensIOS

fileprivate class ViewController: UIViewController {
    func doesSessionExist() {
        if SuperTokens.doesSessionExist() {
            // User is logged in
        } else {
            // User is not logged in
        }
    }
}

```

```
import 'package:supertokens_flutter/supertokens.dart';

Future<bool> doesSessionExist() async {
    return await SuperTokens.doesSessionExist();
}

```

#### [1.6 Add a sign-out action](/content/docs/quickstart?q=BWvr89TAB\#16-add-a-sign-out-action/index.html)

The `signOut` method revokes the session on the frontend and on the backend. Calling this function without a valid session also yields a successful response.

WebMobile

Platform

Web▼

```
import Session from "supertokens-web-js/recipe/session";

async function logout() {
  await Session.signOut();
  window.location.href = "/auth"; // or to wherever your logic page is
}

```

```
import SuperTokens from "supertokens-react-native";

async function logout() {
  await SuperTokens.signOut();
  // navigate to the login screen..
}

```

```
import android.app.Application
import com.supertokens.session.SuperTokens

class MainApplication: Application() {
    fun logout() {
        SuperTokens.signOut(this);
        // navigate to the login screen..
    }
}

```

```
import UIKit
import SuperTokensIOS

fileprivate class ViewController: UIViewController {
  func signOut() {
    SuperTokens.signOut(completionHandler: {
        error in

if error != nil {
            // handle error
        } else {
            // Signed out successfully
        }
    })
  }
}

```

```
import 'package:supertokens_flutter/supertokens.dart';

Future<void> signOut() async {
  await SuperTokens.signOut(
    completionHandler: (error) {
      // handle error if any
    }
  );
}

```

- On success, the `signOut` function does not redirect the user to another page, so you must redirect the user yourself.
- The `signOut` function calls the sign out API exposed by the session recipe on the backend.
- If you call the `signOut` function whilst the access token has expired, but the refresh token still exists, our SDKs do an automatic session refresh before revoking the session.

### [2\. Integrate the backend SDK](/content/docs/quickstart?q=BWvr89TAB\#2-integrate-the-backend-sdk/index.html)

Let’s go through the changes required so that your backend can expose the **SuperTokens** authentication features.

#### [2.1 Install the backend SDK](/content/docs/quickstart?q=BWvr89TAB\#backend-install-sdk/index.html)

Run the following command in your terminal to install the package.

Node.jsGoPython

Language

Node.js▼

Package manager

npm▼

```
npm i -s supertokens-node

```

```
yarn add supertokens-node

```

```
pnpm add supertokens-node

```

```
bun add supertokens-node

```

```
go get github.com/supertokens/supertokens-golang

```

```
pip install supertokens-python

```

#### [2.2 Initialize the backend SDK](/content/docs/quickstart?q=BWvr89TAB\#22-initialize-the-backend-sdk/index.html)

You will have to initialize the **Backend SDK** alongside the code that starts your server.
The init call will include [configuration details](/content/docs/references/backend-sdks/reference#sdk-configuration/index.html) for your app, how the backend will connect to the **SuperTokens Core**, as well as the **Recipes** that will be used in your setup.

Node.jsGoPython

Language

Node.js▼

Node.js framework

Express▼

```
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from "supertokens-node/recipe/emailpassword";

supertokens.init({
  framework: "express",
  supertokens: {
    // We use try.supertokens for demo purposes.
    // At the end of the tutorial we will show you how to create
    // your own SuperTokens core instance and then update your config.
    connectionURI: "https://try.supertokens.io",
    // 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: [\
    EmailPassword.init(), // initializes signin / sign up features\
    Session.init(), // initializes session features\
  ],
});

```

supertokens.init({
  framework: "hapi",
  supertokens: {
    // We use try.supertokens for demo purposes.
    // At the end of the tutorial we will show you how to create
    // your own SuperTokens core instance and then update your config.
    connectionURI: "https://try.supertokens.io",
    // 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: [\
    EmailPassword.init(), // initializes signin / sign up features\
    Session.init(), // initializes session features\
  ],
});

```

supertokens.init({
  framework: "fastify",
  supertokens: {
    // We use try.supertokens for demo purposes.
    // At the end of the tutorial we will show you how to create
    // your own SuperTokens core instance and then update your config.
    connectionURI: "https://try.supertokens.io",
    // 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: [\
    EmailPassword.init(), // initializes signin / sign up features\
    Session.init(), // initializes session features\
  ],
});

```

supertokens.init({
  framework: "koa",
  supertokens: {
    // We use try.supertokens for demo purposes.
    // At the end of the tutorial we will show you how to create
    // your own SuperTokens core instance and then update your config.
    connectionURI: "https://try.supertokens.io",
    // 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: [\
    EmailPassword.init(), // initializes signin / sign up features\
    Session.init(), // initializes session features\
  ],
});

```

supertokens.init({
  framework: "loopback",
  supertokens: {
    // We use try.supertokens for demo purposes.
    // At the end of the tutorial we will show you how to create
    // your own SuperTokens core instance and then update your config.
    connectionURI: "https://try.supertokens.io",
    // 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: [\
    EmailPassword.init(), // initializes signin / sign up features\
    Session.init(), // initializes session features\
  ],
});

```

```
  import (
    "github.com/supertokens/supertokens-golang/recipe/emailpassword"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/supertokens"
  )

func main() {
      apiBasePath := "/auth"
      websiteBasePath := "/auth"
      err := supertokens.Init(supertokens.TypeInput{
          Supertokens: &supertokens.ConnectionInfo{
          // We use try.supertokens for demo purposes.
          // At the end of the tutorial we will show you how to create
          // your own SuperTokens core instance and then update your config.
          ConnectionURI: "https://try.supertokens.io",
          // 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{
            emailpassword.Init(nil),
            session.Init(nil),
          },
      })

if err != nil {
        panic(err.Error())
      }
  }

```

```
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import emailpassword, session

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(
        # We use try.supertokens for demo purposes.
        # At the end of the tutorial we will show you how to create
        # your own SuperTokens core instance and then update your config.
        connection_uri="https://try.supertokens.io",
        # api_key: <YOUR_API_KEY>
    ),
    framework='fastapi',
    recipe_list=[\
	    session.init(), # initializes session features\
        emailpassword.init()\
    ],
    mode='asgi' # use wsgi if you are running using gunicorn
)

```

```
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import emailpassword, session

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(
        # We use try.supertokens for demo purposes.
        # At the end of the tutorial we will show you how to create
        # your own SuperTokens core instance and then update your config.
        connection_uri="https://try.supertokens.io",
        # api_key: <YOUR_API_KEY>
    ),
    framework='flask',
    recipe_list=[\
	    session.init(), # initializes session features\
        emailpassword.init()\
    ]
)

```

```
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import emailpassword, session

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(
        # We use try.supertokens for demo purposes.
        # At the end of the tutorial we will show you how to create
        # your own SuperTokens core instance and then update your config.
        connection_uri="https://try.supertokens.io",
        # api_key: <YOUR_API_KEY>
    ),
    framework='django',
    recipe_list=[\
	    session.init(), # initializes session features\
        emailpassword.init()\
    ],
    mode='asgi' # use wsgi if you are running django server in sync mode
)

```

#### [2.3 Add the SuperTokens APIs and configure CORS](/content/docs/quickstart?q=BWvr89TAB\#23-add-the-supertokens-apis-and-configure-cors/index.html)

Now that the SDK is initialized you need to expose the endpoints that will be used by the frontend SDKs.
Besides this, your server’s CORS, Cross-Origin Resource Sharing, settings should be updated to allow the use of the authentication headers required by **SuperTokens**.

Node.js

Hapi

Register the `plugin`.

Fastify

Register the `plugin`. Also register [`@fastify/formbody`](https://github.com/fastify/fastify-formbody) plugin.

Koa

LoopBack

Go

Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below.

Python

FastAPI

Use the `Middleware` ( **BEFORE all your routes**) and the `get_all_cors_headers()` functions as shown below.

Flask

- Use the `Middleware` ( **BEFORE all your routes and after calling init function**) and the `get_all_cors_headers()` functions as shown below.
- Add a route to catch all paths and return a 404. This is needed because if we don’t add this, then OPTIONS request for the APIs exposed by the `Middleware` will return a `404`.

Django

##### [Configure Django CORS](/content/docs/quickstart?q=BWvr89TAB\#backend-python-django-cors/index.html)

Use the `Middleware` and the `get_all_cors_headers()` functions as shown below in your `settings.py`.

Node.jsGoPython

Language

Node.js▼

Node.js framework

Express▼

```
import express from "express";
import cors from "cors";
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/express";

let app = express();

app.use(
  cors({
    origin: "<YOUR_WEBSITE_DOMAIN>",
    allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
    credentials: true,
  }),
);

// IMPORTANT: CORS should be before the below line.
app.use(middleware());

// ...your API routes

```

```
import Hapi from "@hapi/hapi";
import supertokens from "supertokens-node";
import { plugin } from "supertokens-node/framework/hapi";

let server = Hapi.server({
  port: 8000,
  routes: {
    cors: {
      origin: ["<YOUR_WEBSITE_DOMAIN>"],
      additionalHeaders: [...supertokens.getAllCORSHeaders()],
      credentials: true,
    },
  },
});

(async () => {
  await server.register(plugin);

await server.start();
})();

// ...your API routes

```

```
import cors from "@fastify/cors";
import supertokens from "supertokens-node";
import { plugin } from "supertokens-node/framework/fastify";
import formDataPlugin from "@fastify/formbody";

import fastifyImport from "fastify";

let fastify = fastifyImport();

// ...other middlewares
fastify.register(cors, {
  origin: "<YOUR_WEBSITE_DOMAIN>",
  allowedHeaders: ["Content-Type", ...supertokens.getAllCORSHeaders()],
  credentials: true,
});

(async () => {
  await fastify.register(formDataPlugin);
  await fastify.register(plugin);

await fastify.listen({ port: 8000 });
})();

// ...your API routes

```

```
import Koa from "koa";
import cors from "@koa/cors";
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/koa";

let app = new Koa();

app.use(
  cors({
    origin: "<YOUR_WEBSITE_DOMAIN>",
    allowHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
    credentials: true,
  }),
);

app.use(middleware());

// ...your API routes

```

```
import { RestApplication } from "@loopback/rest";
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/loopback";

let app = new RestApplication({
  rest: {
    cors: {
      origin: "<YOUR_WEBSITE_DOMAIN>",
      allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
      credentials: true,
    },
  },
});

app.middleware(middleware);

// ...your API routes

```

```
import (
	"net/http"
	"strings"

"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
    // SuperTokens init...

http.ListenAndServe("SERVER ADDRESS", corsMiddleware(
		supertokens.Middleware(http.HandlerFunc(func(rw http.ResponseWriter,
        r *http.Request) {
			// TODO: Handle your APIs..

}))))
}

func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(response http.ResponseWriter, r *http.Request) {
		response.Header().Set("Access-Control-Allow-Origin", "<YOUR_WEBSITE_DOMAIN>")
		response.Header().Set("Access-Control-Allow-Credentials", "true")
		if r.Method == "OPTIONS" {
			// we add content-type + other headers used by SuperTokens
			response.Header().Set("Access-Control-Allow-Headers",
				strings.Join(append([]string{"Content-Type"},
					supertokens.GetAllCORSHeaders()...), ","))
			response.Header().Set("Access-Control-Allow-Methods", "*")
			response.Write([]byte(""))
		} else {
			next.ServeHTTP(response, r)
		}
	})
}

```

```
import (
	"net/http"

"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
    // SuperTokens init...

router := gin.New()

// CORS
	router.Use(cors.New(cors.Config{
		AllowOrigins: []string{"<YOUR_WEBSITE_DOMAIN>"},
		AllowMethods: []string{"GET", "POST", "DELETE", "PUT", "OPTIONS"},
		AllowHeaders: append([]string{"content-type"},
			supertokens.GetAllCORSHeaders()...),
		AllowCredentials: true,
	}))

// Adding the SuperTokens middleware
	router.Use(func(c *gin.Context) {
		supertokens.Middleware(http.HandlerFunc(
			func(rw http.ResponseWriter, r *http.Request) {
				c.Next()
			})).ServeHTTP(c.Writer, c.Request)
		// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
		c.Abort()
	})

// Add APIs and start server
}

```

```
import (
	"github.com/go-chi/chi"
	"github.com/go-chi/cors"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
    // SuperTokens init...

r := chi.NewRouter()

// CORS
	r.Use(cors.Handler(cors.Options{
		AllowedOrigins: []string{"<YOUR_WEBSITE_DOMAIN>"},
		AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders: append([]string{"Content-Type"},
			supertokens.GetAllCORSHeaders()...),
		AllowCredentials: true,
	}))

// SuperTokens Middleware
	r.Use(supertokens.Middleware)

// Add APIs and start server
}

```

```
import (
	"net/http"

"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
	// SuperTokens init...

// TODO: Add APIs

router := mux.NewRouter()

// Adding handlers.CORS(options)(supertokens.Middleware(router)))
	http.ListenAndServe("SERVER ADDRESS", handlers.CORS(
		handlers.AllowedHeaders(append([]string{"Content-Type"},
			supertokens.GetAllCORSHeaders()...)),
		handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"}),
		handlers.AllowedOrigins([]string{"<YOUR_WEBSITE_DOMAIN>"}),
		handlers.AllowCredentials(),
	)(supertokens.Middleware(router)))
}

```

```
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

from supertokens_python import get_all_cors_headers
from supertokens_python.framework.fastapi import get_middleware

app = FastAPI()
app.add_middleware(get_middleware())

# TODO: Add APIs

app.add_middleware(
    CORSMiddleware,
    allow_origins=[\
        "<YOUR_WEBSITE_DOMAIN>"\
    ],
    allow_credentials=True,
    allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
    allow_headers=["Content-Type"] + get_all_cors_headers(),
)

# TODO: start server

```

```
from supertokens_python import get_all_cors_headers
from flask import Flask, abort
from flask_cors import CORS
from supertokens_python.framework.flask import Middleware

app = Flask(__name__)
Middleware(app)

# TODO: Add APIs

CORS(
    app=app,
    origins=[\
        "<YOUR_WEBSITE_DOMAIN>"\
    ],
    supports_credentials=True,
    allow_headers=["Content-Type"] + get_all_cors_headers(),
)

# This is required since if this is not there, then OPTIONS requests for
# the APIs exposed by the supertokens' Middleware will return a 404
@app.route('/', defaults={'u_path': ''})
@app.route('/<path:u_path>')
def catch_all(u_path: str):
    abort(404)

# TODO: start server

```

```
from typing import List

from corsheaders.defaults import default_headers

from supertokens_python import get_all_cors_headers

CORS_ORIGIN_WHITELIST = [\
    "<YOUR_WEBSITE_DOMAIN>"\
]

CORS_ALLOW_CREDENTIALS = True

CORS_ALLOWED_ORIGINS = [\
    "<YOUR_WEBSITE_DOMAIN>"\
]

CORS_ALLOW_HEADERS: List[str] = list(default_headers) + [\
    "Content-Type"\
] + get_all_cors_headers()

INSTALLED_APPS = [\
    'corsheaders',\
    'supertokens_python'\
]

MIDDLEWARE = [\
    'corsheaders.middleware.CorsMiddleware',\
    ...,\
    'supertokens_python.framework.django.django_middleware.middleware',\
]
# TODO: start server

```

You can review all the endpoints that are added through the use of **SuperTokens** by visiting the [API Specs](https://app.swaggerhub.com/apis/supertokens/FDI).

#### [2.4 Add the SuperTokens error handler](/content/docs/quickstart?q=BWvr89TAB\#24-add-the-supertokens-error-handler/index.html)

Depending on the language and framework that you are using, you might need to add a custom error handler to your server.
The handler will catch all the authentication related errors and return proper HTTP responses that can be parsed by the frontend SDKs.

Node.js

Express

Hapi

No additional `errorHandler` is required.

Fastify

Add the `errorHandler` **Before all your routes and plugin registration**

Koa

No additional `errorHandler` is required.

LoopBack

No additional `errorHandler` is required.

Go

Python

Node.js

Node.js framework

Express▼

```
import express, { Request, Response, NextFunction } from "express";
import { errorHandler } from "supertokens-node/framework/express";

let app = express();

// ...your API routes

// Add this AFTER all your routes
app.use(errorHandler());

// your own error handler
app.use((err: unknown, req: Request, res: Response, next: NextFunction) => {
  /* ... */
});

```

```
import Fastify from "fastify";
import { errorHandler } from "supertokens-node/framework/fastify";

let fastify = Fastify();

fastify.setErrorHandler(errorHandler());

// ...your API routes

```

#### [2.5 Secure application routes](/content/docs/quickstart?q=BWvr89TAB\#25-secure-application-routes/index.html)

Now that your server can authenticate users, the final step that you need to take care of is to prevent unauthorized access to certain parts of the application.

Node.js

For your APIs that require a user to be logged in, use the `verifySession` middleware.

Go

For your APIs that require a user to be logged in, use the `VerifySession` middleware.

Python

For your APIs that require a user to be logged in, use the `verify_session` middleware.

Node.jsGoPython

Language

Node.js▼

Node.js framework

Express▼

```
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";

let app = express();

app.post("/like-comment", verifySession(), (req: SessionRequest, res) => {
  let userId = req.session!.getUserId();
  //....
});

```

```
import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";

let server = Hapi.server({ port: 8000 });

server.route({
  path: "/like-comment",
  method: "post",
  options: {
    pre: [\
      {\
        method: verifySession(),\
      },\
    ],
  },
  handler: async (req: SessionRequest, res) => {
    let userId = req.session!.getUserId();
    //...
  },
});

```

```
import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import { SessionRequest } from "supertokens-node/framework/fastify";

let fastify = Fastify();

fastify.post(
  "/like-comment",
  {
    preHandler: verifySession(),
  },
  (req: SessionRequest, res) => {
    let userId = req.session!.getUserId();
    //....
  },
);

```

```
import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";

let router = new KoaRouter();

router.post("/like-comment", verifySession(), (ctx: SessionContext, next) => {
  let userId = ctx.session!.getUserId();
  //....
});

```

```
import { inject, intercept } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";

class LikeComment {
  constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) {}
  @post("/like-comment")
  @intercept(verifySession())
  @response(200)
  handler() {
    let userId = (this.ctx as SessionContext).session!.getUserId();
    //....
  }
}

```

```
import (
	"fmt"
	"net/http"

"github.com/supertokens/supertokens-golang/recipe/session"
)

func main() {
	_ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		// Wrap the API handler in session.VerifySession
		session.VerifySession(nil, likeCommentAPI).ServeHTTP(rw, r)
	})
}

func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
	// retrieve the session object as shown below
	sessionContainer := session.GetSessionFromRequestContext(r.Context())

userID := sessionContainer.GetUserID()

fmt.Println(userID)
}

```

```
import (
	"fmt"
	"net/http"

"github.com/gin-gonic/gin"
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)

func main() {
	router := gin.New()

// Wrap the API handler in session.VerifySession
	router.POST("/likecomment", verifySession(nil), likeCommentAPI)
}

// This is a function that wraps the supertokens verification function
// to work the gin
func verifySession(options *sessmodels.VerifySessionOptions) gin.HandlerFunc {
	return func(c *gin.Context) {
		session.VerifySession(options, func(rw http.ResponseWriter, r *http.Request) {
			c.Request = c.Request.WithContext(r.Context())
			c.Next()
		})(c.Writer, c.Request)
		// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
		c.Abort()
	}
}

func likeCommentAPI(c *gin.Context) {
	// retrieve the session object as shown below
	sessionContainer := session.GetSessionFromRequestContext(c.Request.Context())

userID := sessionContainer.GetUserID()

fmt.Println(userID)
}

```

```
import (
	"fmt"
	"net/http"

"github.com/go-chi/chi"
	"github.com/supertokens/supertokens-golang/recipe/session"
)

func main() {
	r := chi.NewRouter()

// Wrap the API handler in session.VerifySession
	r.Post("/likecomment", session.VerifySession(nil, likeCommentAPI))
}

userID := sessionContainer.GetUserID()

fmt.Println(userID)
}

```

```
import (
	"fmt"
	"net/http"

"github.com/gorilla/mux"
	"github.com/supertokens/supertokens-golang/recipe/session"
)

func main() {
	router := mux.NewRouter()

// Wrap the API handler in session.VerifySession
	router.HandleFunc("/likecomment", session.VerifySession(nil, likeCommentAPI)).Methods(http.MethodPost)
}

userID := sessionContainer.GetUserID()

fmt.Println(userID)
}

```

```
from fastapi import Depends

from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.fastapi import verify_session

@app.post('/like_comment')
async def like_comment(session: SessionContainer = Depends(verify_session())):
    user_id = session.get_user_id()

print(user_id)

```

```
from flask import g

from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.flask import verify_session

@app.route('/update-jwt', methods=['POST'])
@verify_session()
def like_comment():
    session: SessionContainer = g.supertokens

user_id = session.get_user_id()

print(user_id)

```

```
from typing import cast

from django.http import HttpRequest

from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.django.asyncio import verify_session

@verify_session()
async def like_comment(request: HttpRequest):
    session: SessionContainer = cast(SessionContainer, request.supertokens)

user_id = session.get_user_id()

print(user_id)

```

The middleware function returns a `401` to the frontend if a session doesn’t exist, or if the access token has expired, in which case, our frontend SDK automatically refreshes the session.

In case of successful session verification, you get access to a `session` object using which you can get the user’s ID, or manipulate the session information.

### [3\. Configure the Core Service](/content/docs/quickstart?q=BWvr89TAB\#3-configure-the-core-service/index.html)

If you have signed up and deployed a SuperTokens environment already, you can skip this step.
Otherwise, please follow these instructions to use the correct **SuperTokens Core** instance in your application.

The steps show you how to connect to a **SuperTokens Managed Service Environment**.
If you want to self host the core instance please check the [following guide](/content/docs/deployment/self-host-supertokens/index.html).

#### [3.1 Sign up for a SuperTokens account](/content/docs/quickstart?q=BWvr89TAB\#31-sign-up-for-a-supertokens-account/index.html)

Open this [page](/content/auth/index.html) in order to access the account creation page.
Select the account that you want to use and wait for the action to complete.

#### [3.2 Create a deployment](/content/docs/quickstart?q=BWvr89TAB\#32-create-a-deployment/index.html)

After signing in, open the SuperTokens dashboard and select **Managed**. Enter a name for the deployment, select the region closest to your backend services, and click **Deploy Core**.

Our internal service will deploy a separate environment based on your selection.
After this process is complete, open the new deployment from the list.

#### [3.3 Connect the backend SDK with SuperTokens](/content/docs/quickstart?q=BWvr89TAB\#33-connect-the-backend-sdk-with-supertokens/index.html)

In the SuperTokens dashboard, open the newly created deployment and select **Overview**. In **Connection Information**, copy the **Connection URI** and one of the **API Keys**, then use them as `connectionURI` and `apiKey` in your backend SDK configuration. If no suitable key exists, click **Generate Key** to create one.

Node.jsGoPython

Language

Node.js▼

```
import supertokens from "supertokens-node";

supertokens.init({
  supertokens: {
    connectionURI: "<CONNECTION_URI>",
    apiKey: "<API_KEY>",
  },
  appInfo: {
    apiDomain: "...",
    appName: "...",
    websiteDomain: "...",
  },
  recipeList: [],
});

```

```
import "github.com/supertokens/supertokens-golang/supertokens"

func main() {
	supertokens.Init(supertokens.TypeInput{
		Supertokens: &supertokens.ConnectionInfo{
            ConnectionURI: "<CONNECTION_URI>",
            APIKey:        "<API_KEY>",
		},
	})
}

```

```
from supertokens_python import init, InputAppInfo, SupertokensConfig

init(
   app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
   supertokens_config=SupertokensConfig(
      connection_uri='<CONNECTION_URI>',
      api_key='<API_KEY>'
   ),
   framework='...',
   recipe_list=[\
      #...\
   ]
)

```

## [Next steps](/content/docs/quickstart?q=BWvr89TAB\#next-steps/index.html)

Review this SuperTokens integration for production readiness.

Copy promptCopied

Review this repository’s SuperTokens integration for production readiness. Inspect Core deployment configuration, API keys, environment separation, HTTPS, secret handling, session security, CORS, cookies, email or SMS delivery, rate limits, logging, and error handling. Check that frontend and backend recipes match and that protected routes are actually protected. Run the relevant tests, typechecks, and build. Report findings by severity with file references, then make only safe fixes that are clearly required.

Now that you have completed the quickstart, continue configuring SuperTokens for your application’s authentication and authorization requirements.

[Authentication Methods\\
\\
Add passwordless, social, enterprise, or machine-to-machine authentication.](/content/docs/authentication/overview/index.html) [Email Verification\\
\\
Verify user email addresses during sign-up.](/content/docs/additional-verification/email-verification/initial-setup/index.html) [Multi-Factor Authentication\\
\\
Add more authentication factors to your sign-in process.](/content/docs/additional-verification/mfa/introduction/index.html) [Session Management\\
\\
Configure session security, storage, and advanced workflows.](/content/docs/post-authentication/session-management/introduction/index.html) [User Management\\
\\
Manage users through the SuperTokens Dashboard.](/content/docs/post-authentication/dashboard/introduction/index.html) [Deployment\\
\\
Run SuperTokens as a managed service or inside your infrastructure.](/content/docs/deployment/self-host-supertokens/index.html)
