---
title: Quickstart Guide
description: Add SuperTokens authentication to your frontend and backend, then prepare the integration for production.
sidebar:
  icon: zap
  order: 30
---

## Overview

<Prompt
  description="Ask an agent to integrate SuperTokens into an existing application."
  actions={["copy"]}
>
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.
</Prompt>

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

### 1. Integrate the frontend SDK

#### Frontend integration summary

- React uses `supertokens-auth-react`; Angular and Vue use `supertokens-web-js`.
- Initialize the authentication and Session recipes. React applications also wrap their component tree with `SuperTokensWrapper`.
- Render the prebuilt login UI on `/auth`.
- The SDK intercepts `fetch` and XHR requests to manage session tokens automatically. Web sessions use HTTP-only cookies by default, with header-based authentication available as an alternative.

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.

<UITypeSwitch />

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

<AnchoredHeading id="prebuilt-ui-install-sdk" level={4}>1.1 Install the SDK</AnchoredHeading>

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

<CodeGroup group="frontend-prebuilt-ui">
```bash title="Reactjs" option="package-managers:npm"
  npm i -s supertokens-auth-react
```

```bash title="Reactjs" option="package-managers:yarn"
yarn add supertokens-auth-react supertokens-web-js
```

```bash title="Reactjs" option="package-managers:pnpm"
pnpm add supertokens-auth-react supertokens-web-js
```

```bash title="Reactjs" option="package-managers:bun"
bun add supertokens-auth-react supertokens-web-js
```

```bash title="Angular" option="package-managers:npm"
npm i -s supertokens-web-js
```

```bash title="Angular" option="package-managers:yarn"
yarn add supertokens-web-js
```

```bash title="Angular" option="package-managers:pnpm"
pnpm add supertokens-web-js
```

```bash title="Angular" option="package-managers:bun"
bun add supertokens-web-js
```

```bash title="Vue" option="package-managers:npm"
npm i -s supertokens-web-js
```

```bash title="Vue" option="package-managers:yarn"
yarn add supertokens-web-js
```

```bash title="Vue" option="package-managers:pnpm"
pnpm add supertokens-web-js
```

```bash title="Vue" option="package-managers:bun"
bun add supertokens-web-js
```
</CodeGroup>

#### 1.2 Initialize the SDK

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="reactjs">
    In your main application file call the `SuperTokens.init` function to initialize the SDK.
    The `init` call includes the [main configuration details](/references/frontend-sdks/reference#sdk-configuration), 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.
  </ContentOption>
  <ContentOption title="Angular" value="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.

    <AnchoredHeading id="prebuilt-angular-auth-route" level={5}>Creating the `/auth` route</AnchoredHeading>

    - Use the Angular CLI to generate a new route
  </ContentOption>
  <ContentOption title="Vue" value="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:
  </ContentOption>
</DependentContent>

<CodeGroup group="frontend-prebuilt-ui">
```tsx title="Reactjs"
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>;
  }
}
```

```bash title="Angular"
      ng generate module auth --route auth --module app.module
```

```tsx check=false reason="This is a Vue single-file component containing both TypeScript and template markup." title="Vue"
  <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>
```
</CodeGroup>

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="reactjs"></ContentOption>
  <ContentOption title="Angular" value="angular">
    - Add the following code to your `auth` angular component
  </ContentOption>
  <ContentOption title="Vue" value="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.
  </ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-prebuilt-ui">
```tsx check=false reason="Requires surrounding quickstart application context" title="Angular"
    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);
      }
    }
```

```tsx check=false reason="Requires surrounding quickstart application context" title="Vue"
    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");
```
</CodeGroup>

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="reactjs"></ContentOption>
  <ContentOption title="Angular" value="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.
  </ContentOption>
  <ContentOption title="Vue" value="vue"></ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-prebuilt-ui">
```tsx title="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()],
});
```
</CodeGroup>

#### 1.3 Configure routing

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="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.

    <DependentContent passive group="react-router">
      <ContentOption title="With React Router" value="yes">
        Call the `getSuperTokensRoutesForReactRouterDom` method from within any `react-router-dom` `Routes` component.
      </ContentOption>
      <ContentOption title="Without React Router" value="no">
        Add the route handling shown below to your root-level `render` function.
      </ContentOption>
    </DependentContent>
  </ContentOption>
  <ContentOption title="Angular" value="angular">
    Update your angular router so that all auth related requests load the `auth` component
  </ContentOption>
  <ContentOption title="Vue" value="vue">
    Update your Vue router so that all auth related requests load the `AuthView` component
  </ContentOption>
</DependentContent>

<CodeGroup group="frontend-prebuilt-ui">
```tsx title="Reactjs" option="react-router:yes"
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>
    );
  }
}
```

```tsx title="Reactjs" option="react-router:no"
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>;
  }
}
```

```tsx check=false reason="Requires surrounding quickstart application context" title="Angular"
    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 {}
```

```tsx check=false reason="Requires surrounding quickstart application context" title="Vue"
    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;
```
</CodeGroup>

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="reactjs">
    <DependentContent passive group="react-router">
      <ContentOption title="With React Router" value="yes">
        :::note[If you are using `useRoutes`, `createBrowserRouter` or have routes defined in a different file, you need to adjust the code sample.]
        Please see [this issue](https://github.com/supertokens/supertokens-auth-react/issues/581#issuecomment-1246998493) for further details.
        :::
      </ContentOption>
      <ContentOption title="Without React Router" value="no"></ContentOption>
    </DependentContent>
  </ContentOption>
  <ContentOption title="Angular" value="angular"></ContentOption>
  <ContentOption title="Vue" value="vue"></ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-prebuilt-ui">
```tsx title="Reactjs" option="react-router:yes"
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>
  );
}
```
</CodeGroup>

#### 1.4 Handle session tokens

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](/post-authentication/session-management/switch-between-cookies-and-header-authentication).

#### 1.5 Secure application routes

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.

<DependentContent passive group="frontend-prebuilt-ui">
  <ContentOption title="Reactjs" value="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.
  </ContentOption>
  <ContentOption title="Angular" value="angular">
    You can use the `doesSessionExist` function to check if a session exists in all your routes.
  </ContentOption>
  <ContentOption title="Vue" value="vue">
    You can use the `doesSessionExist` function to check if a session exists in all your routes.
  </ContentOption>
</DependentContent>

<CodeGroup group="frontend-prebuilt-ui">
```tsx check=false reason="Requires surrounding quickstart application context" title="Reactjs"
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>
    );
  }
}
```

```tsx title="Angular"
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
  }
}
```

```tsx title="Vue"
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
  }
}
```
</CodeGroup>

</VariantContent>

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

<AnchoredHeading id="custom-ui-install-sdk" level={4}>1.1 Install the SDK</AnchoredHeading>

Use the following command to install the required package.

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web">
    <DependentContent passive group="install-method">
      <ContentOption title="npm" value="npm"></ContentOption>
    </DependentContent>
  </ContentOption>
  <ContentOption title="Mobile" value="mobile">
    :::info
    If you want to implement a common authentication experience for both web and mobile, please look at our [**Unified Login guide**](/authentication/unified-login/introduction).
    :::

    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="android">Add to your `settings.gradle`:</ContentOption>
      <ContentOption title="iOS" value="ios">
        <AnchoredHeading id="custom-ui-ios-cocoapods" level={5}>Using CocoaPods</AnchoredHeading>

        Add the CocoaPods dependency to your `Podfile`
      </ContentOption>
      <ContentOption title="Flutter" value="flutter">Add the dependency to your pubspec.yaml</ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup group="frontend-custom-ui">
```bash title="Web" option="install-method:npm"
npm i -s supertokens-web-js
```

```bash title="Mobile" option="mobile-frameworks:reactnative"
npm i -s supertokens-react-native@5.1.5 @react-native-async-storage/async-storage@2.2.0
```

```bash title="Mobile" option="mobile-frameworks:android"
dependencyResolutionManagement {
    ...
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
```

```bash title="Mobile" option="mobile-frameworks:ios"
pod 'SuperTokensIOS', '0.4.2'
```

```bash title="Mobile" option="mobile-frameworks:flutter"
supertokens_flutter: 0.6.5
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="android">
        Add the following to you app level's `build.gradle`:
      </ContentOption>
      <ContentOption title="iOS" value="ios">
        ##### Using Swift Package Manager

        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:
      </ContentOption>
      <ContentOption title="Flutter" value="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).
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-custom-ui">
```bash title="Mobile" option="mobile-frameworks:android"
implementation 'com.github.supertokens:supertokens-android:0.5.3'
```

```bash title="Mobile" option="mobile-frameworks:ios"
https://github.com/supertokens/supertokens-ios
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="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).
      </ContentOption>
      <ContentOption title="iOS" value="ios"></ContentOption>
      <ContentOption title="Flutter" value="flutter"></ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

#### 1.2 Initialize SuperTokens

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

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="android">
        Add the `SuperTokens.init` function call at the start of your application.
      </ContentOption>
      <ContentOption title="iOS" value="ios"></ContentOption>
      <ContentOption title="Flutter" value="flutter"></ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

  <CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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()],
});
```

```tsx title="Mobile" option="mobile-frameworks:reactnative"
import SuperTokens from "supertokens-react-native";

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

```kotlin title="Mobile" option="mobile-frameworks:android"
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()
    }
}
```

```swift title="Mobile" option="mobile-frameworks:ios"
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
    }

}
```

```dart title="Mobile" option="mobile-frameworks:flutter"
import 'package:supertokens_flutter/supertokens.dart';

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

#### 1.3 Add the login UI

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

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="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.
  </ContentOption>
  <ContentOption title="Mobile" value="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.
  </ContentOption>
</DependentContent>

  <CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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.");
    }
  }
}
```

```bash title="Mobile"
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"
    }]
}'
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="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.
  </ContentOption>
</DependentContent>

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:

```json
{
  "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

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.

  <CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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.");
    }
  }
}
```

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

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="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.
  </ContentOption>
</DependentContent>

##### 1.3.2 Add the sign-in form

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="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.
  </ContentOption>
  <ContentOption title="Mobile" value="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.
  </ContentOption>
</DependentContent>

  <CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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.");
    }
  }
}
```

```bash title="Mobile"
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"
    }]
}'
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="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.
  </ContentOption>
</DependentContent>

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

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

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web">
    :::success[No action required.]
    :::

    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.
  </ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative">
        Our frontend SDK handles everything for you. You only need to make sure that you have added our network interceptors as shown below

        :::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.]
        :::

        ###### Axios

        ###### Using a custom Axios instance
      </ContentOption>
      <ContentOption title="Android" value="android">
        ###### HttpURLConnection
      </ContentOption>
      <ContentOption title="iOS" value="ios">
        ###### `URLSession`

        ###### Using `URLSession.shared`
      </ContentOption>
      <ContentOption title="Flutter" value="flutter">
        ###### `http`

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

<CodeGroup group="frontend-custom-ui">
```tsx title="Mobile" option="mobile-frameworks: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");
}
```

```kotlin title="Mobile" option="mobile-frameworks:android"
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
        }
    }
}
```

```swift title="Mobile" option="mobile-frameworks:ios"
import Foundation
import SuperTokensIOS

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

```dart title="Mobile" option="mobile-frameworks:flutter"
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 response = await http.get(uri);
    // handle response
}
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative">
        ###### Using the global Axios instance

        :::note[You must call `addAxiosInterceptors` on all `axios` imports.]
        :::
      </ContentOption>
      <ContentOption title="Android" value="android">
        :::note[When making network requests you do not need to call `HttpURLConnection.connect` because SuperTokens does this for you.]
        :::

        ###### OkHttp or Retrofit
      </ContentOption>
      <ContentOption title="iOS" value="ios">
        ###### Using a custom `URLSession` instance
      </ContentOption>
      <ContentOption title="Flutter" value="flutter">
        ###### Using a custom HTTP client

        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.
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-custom-ui">
```tsx title="Mobile" option="mobile-frameworks:reactnative"
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");
}
```

```kotlin title="Mobile" option="mobile-frameworks:android"
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
    }
}
```

```swift title="Mobile" option="mobile-frameworks:ios"
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
    }
}
```

```dart title="Mobile" option="mobile-frameworks:flutter"
// Import http from the SuperTokens package
import 'package:supertokens_flutter/http.dart' as 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
}
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative">
        ###### Fetch

        :::success[When using `fetch`, network interceptors are added automatically when you call `supertokens.init`. So no action needed here.]
        :::
      </ContentOption>
      <ContentOption title="Android" value="android">
        :::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.]
        :::
      </ContentOption>
      <ContentOption title="iOS" value="ios">
        ###### Alamofire
      </ContentOption>
      <ContentOption title="Flutter" value="flutter">
        ###### Dio

        ###### Add the SuperTokens interceptor

        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.
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-custom-ui">
```swift title="Mobile" option="mobile-frameworks:ios"
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
    }
}
```

```dart title="Mobile" option="mobile-frameworks:flutter"
import 'package:supertokens_flutter/dio.dart';
import 'package:dio/dio.dart';

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

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="android"></ContentOption>
      <ContentOption title="iOS" value="ios">
        :::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.]
        :::
      </ContentOption>
      <ContentOption title="Flutter" value="flutter">
        ###### Making network requests

        You can make requests as you normally would with `dio`.
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-custom-ui">
```dart title="Mobile" option="mobile-frameworks:flutter"
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
}
```
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
  <ContentOption title="Web" value="web"></ContentOption>
  <ContentOption title="Mobile" value="mobile">
    <DependentContent passive group="mobile-frameworks">
      <ContentOption title="ReactNative" value="reactnative"></ContentOption>
      <ContentOption title="Android" value="android"></ContentOption>
      <ContentOption title="iOS" value="ios"></ContentOption>
      <ContentOption title="Flutter" value="flutter">
        :::note[By default our mobile SDKs use a bearer token in the Authorization header to provide credentials.]
        :::
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

##### Without the Frontend SDK

:::warning[We highly recommend using our frontend SDK to handle session token management. It saves you a lot of time.]
:::

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.

**Cookie**

###### During the Login Action

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:
    ```tsx
    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

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

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:

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

:::note[You may also need to add the `anti-csrf` header to the request if that was provided to you during sign in.]
- The cURL command above shows the `sRefreshToken` cookie as well, but this is added by the web browser automatically, so you don't need to add it explicitly.
:::

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.

**Header (Authorization Bearer)**

###### During the Login Action

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

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

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:

```bash
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

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

<CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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
  }
}
```

```tsx title="Mobile" option="mobile-frameworks:reactnative"
import SuperTokens from "supertokens-react-native";

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

```kotlin title="Mobile" option="mobile-frameworks:android"
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
        }
    }
}
```

```swift title="Mobile" option="mobile-frameworks:ios"
import UIKit
import SuperTokensIOS

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

```dart title="Mobile" option="mobile-frameworks:flutter"
import 'package:supertokens_flutter/supertokens.dart';

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

#### 1.6 Add a sign-out action

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.

  <CodeGroup group="frontend-custom-ui">
```tsx title="Web" option="install-method:npm"
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
}
```

```tsx title="Mobile" option="mobile-frameworks:reactnative"
import SuperTokens from "supertokens-react-native";

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

```kotlin title="Mobile" option="mobile-frameworks:android"
import android.app.Application
import com.supertokens.session.SuperTokens

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

```swift title="Mobile" option="mobile-frameworks:ios"
import UIKit
import SuperTokensIOS

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

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

```dart title="Mobile" option="mobile-frameworks:flutter"
import 'package:supertokens_flutter/supertokens.dart';

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

- 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.

</VariantContent>

### 2. Integrate the backend SDK

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

<AnchoredHeading id="backend-install-sdk" level={4}>2.1 Install the backend SDK</AnchoredHeading>

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

<CodeGroup group="backend-language">
```bash title="Node.js" option="package-managers:npm"
npm i -s supertokens-node
```

```bash title="Node.js" option="package-managers:yarn"
yarn add supertokens-node
```

```bash title="Node.js" option="package-managers:pnpm"
pnpm add supertokens-node
```

```bash title="Node.js" option="package-managers:bun"
bun add supertokens-node
```

```bash title="Go"
go get github.com/supertokens/supertokens-golang
```

```bash title="Python"
pip install supertokens-python
```
</CodeGroup>

:::info[Official backend SDKs are available for **Node.js**, **Python**, and **Go**.]
For other languages, create a separate authentication service. Our [other frameworks guide](/references/backend-sdks/other-frameworks) explains this approach.

:::

#### 2.2 Initialize the backend SDK

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

<CodeGroup group="backend-language">
```tsx title="Node.js" option="node-frameworks: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
  ],
});
```

```tsx title="Node.js" option="node-frameworks:hapi"
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from "supertokens-node/recipe/emailpassword";

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
  ],
});
```

```tsx title="Node.js" option="node-frameworks:fastify"
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from "supertokens-node/recipe/emailpassword";

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
  ],
});
```

```tsx title="Node.js" option="node-frameworks:koa"
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from "supertokens-node/recipe/emailpassword";

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
  ],
});
```

```tsx title="Node.js" option="node-frameworks:loopback"
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from "supertokens-node/recipe/emailpassword";

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
  ],
});
```

```go title="Go"
  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())
      }
  }
```

```python title="Python" option="python-frameworks:fastapi"
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
)
```

```python title="Python" option="python-frameworks:flask"
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()
    ]
)
```

```python title="Python" option="python-frameworks:django"
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
)
```
</CodeGroup>

:::info[Multiple frontend domains]
To handle clients from different domains with the same SuperTokens instance, use the `origin` property in the `appInfo` object instead of `websiteDomain`.
The property accepts a function that receives the original request as an input and should return a valid domain.
Make sure to whitelist all the domains during CORS configuration.

Keep in mind that with this setup, each frontend application will not share authentication sessions.
Users will have to authenticate separately for each domain.
To configure a shared authentication experience between multiple services check the [Unified Login](/authentication/unified-login/introduction) documentation.
:::

#### 2.3 Add the SuperTokens APIs and configure CORS

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**.

<DependentContent passive group="backend-language">
  <ContentOption title="Node.js" value="nodejs">
    <DependentContent passive group="node-frameworks">
      <ContentOption title="Hapi" value="hapi">Register the `plugin`.</ContentOption>
      <ContentOption title="Fastify" value="fastify">
        Register the `plugin`. Also register [`@fastify/formbody`](https://github.com/fastify/fastify-formbody) plugin.
      </ContentOption>
      <ContentOption title="Koa" value="koa">
        :::note[Add the `middleware` BEFORE all your routes.]
        :::
      </ContentOption>
      <ContentOption title="LoopBack" value="loopback">
        :::note[Add the `middleware` BEFORE all your routes.]
        :::
      </ContentOption>
    </DependentContent>
  </ContentOption>
  <ContentOption title="Go" value="go">
    Use the `supertokens.Middleware` and the `supertokens.GetAllCORSHeaders()` functions as shown below.
  </ContentOption>
  <ContentOption title="Python" value="python">
    <DependentContent passive group="python-frameworks">
      <ContentOption title="FastAPI" value="fastapi">
        Use the `Middleware` (**BEFORE all your routes**) and the `get_all_cors_headers()` functions as shown below.
      </ContentOption>
      <ContentOption title="Flask" value="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`.
      </ContentOption>
      <ContentOption title="Django" value="django">
        <AnchoredHeading id="backend-python-django-cors" level={5}>Configure Django CORS</AnchoredHeading>

        Use the `Middleware` and the `get_all_cors_headers()` functions as shown below in your `settings.py`.
      </ContentOption>
    </DependentContent>
  </ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
```tsx title="Node.js" option="node-frameworks: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
```

```tsx title="Node.js" option="node-frameworks:hapi"
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
```

```tsx title="Node.js" option="node-frameworks:fastify"
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
```

```tsx title="Node.js" option="node-frameworks:koa"
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
```

```tsx title="Node.js" option="node-frameworks:loopback"
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
```

```go title="Go" option="go-frameworks:http"
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)
		}
	})
}
```

```go title="Go" option="go-frameworks:gin"
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
}
```

```go title="Go" option="go-frameworks:chi"
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
}
```

```go title="Go" option="go-frameworks:mux"
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)))
}
```

```python title="Python" option="python-frameworks:fastapi"
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
```

```python check=false reason="Requires surrounding quickstart application context" title="Python" option="python-frameworks:flask"
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
```

```python check=false reason="Requires surrounding quickstart application context" title="Python" option="python-frameworks:django"
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
```
</CodeGroup>

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

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.

<DependentContent passive group="backend-language">
  <ContentOption title="Node.js" value="nodejs">
    <DependentContent passive group="node-frameworks">
      <ContentOption title="Express" value="express"></ContentOption>
      <ContentOption title="Hapi" value="hapi">No additional `errorHandler` is required.</ContentOption>
      <ContentOption title="Fastify" value="fastify">
        Add the `errorHandler` **Before all your routes and plugin registration**
      </ContentOption>
      <ContentOption title="Koa" value="koa">No additional `errorHandler` is required.</ContentOption>
      <ContentOption title="LoopBack" value="loopback">No additional `errorHandler` is required.</ContentOption>
    </DependentContent>
  </ContentOption>
  <ContentOption title="Go" value="go">
    :::info[You can skip this step]
    :::
  </ContentOption>
  <ContentOption title="Python" value="python">
    :::info[You can skip this step]
    :::
  </ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
```tsx title="Node.js" option="node-frameworks: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) => {
  /* ... */
});
```

```tsx title="Node.js" option="node-frameworks:fastify"
import Fastify from "fastify";
import { errorHandler } from "supertokens-node/framework/fastify";

let fastify = Fastify();

fastify.setErrorHandler(errorHandler());

// ...your API routes
```
</CodeGroup>

#### 2.5 Secure application routes

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.

<DependentContent passive group="backend-language">
  <ContentOption title="Node.js" value="nodejs">
    For your APIs that require a user to be logged in, use the `verifySession` middleware.
  </ContentOption>
  <ContentOption title="Go" value="go">
    For your APIs that require a user to be logged in, use the `VerifySession` middleware.
  </ContentOption>
  <ContentOption title="Python" value="python">
    For your APIs that require a user to be logged in, use the `verify_session` middleware.
  </ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
```tsx title="Node.js" option="node-frameworks: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();
  //....
});
```

```tsx title="Node.js" option="node-frameworks:hapi"
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();
    //...
  },
});
```

```tsx title="Node.js" option="node-frameworks:fastify"
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();
    //....
  },
);
```

```tsx title="Node.js" option="node-frameworks:koa"
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();
  //....
});
```

```tsx title="Node.js" option="node-frameworks:loopback"
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();
    //....
  }
}
```

```go title="Go" option="go-frameworks:http"
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)
}
```

```go title="Go" option="go-frameworks:gin"
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)
}
```

```go title="Go" option="go-frameworks:chi"
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))
}

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)
}
```

```go title="Go" option="go-frameworks:mux"
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)
}

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)
}
```

```python check=false reason="Requires surrounding quickstart application context" title="Python" option="python-frameworks:fastapi"
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)
```

```python check=false reason="Requires surrounding quickstart application context" title="Python" option="python-frameworks:flask"
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)
```

```python check=false reason="Requires surrounding quickstart application context" title="Python" option="python-frameworks:django"
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)
```
</CodeGroup>

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

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](/deployment/self-host-supertokens).

#### 3.1 Sign up for a SuperTokens account

Open this [page](https://supertokens.com/auth) 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

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.

:::info[The initial setup flow only configures a development environment.]
In order to use SuperTokens in production, you will have to create a separate deployment.

:::

#### 3.3 Connect the backend SDK with SuperTokens

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.

<CodeGroup group="backend-language">
```tsx title="Node.js"
import supertokens from "supertokens-node";

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

```go title="Go"
import "github.com/supertokens/supertokens-golang/supertokens"

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

```

```python check=false reason="Requires surrounding quickstart application context" title="Python"
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=[
      #...
   ]
)
```
</CodeGroup>

## Next steps

<Prompt
  description="Review this SuperTokens integration for production readiness."
  actions={["copy"]}
>
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.
</Prompt>

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

<CardGroup cols={2}>
  <Card title="Authentication Methods" icon="key-round" href="/authentication/overview">
    Add passwordless, social, enterprise, or machine-to-machine authentication.
  </Card>
  <Card title="Email Verification" icon="badge-check" href="/additional-verification/email-verification/initial-setup">
    Verify user email addresses during sign-up.
  </Card>
  <Card title="Multi-Factor Authentication" icon="shield-check" href="/additional-verification/mfa/introduction">
    Add more authentication factors to your sign-in process.
  </Card>
  <Card title="Session Management" icon="refresh-cw" href="/post-authentication/session-management/introduction">
    Configure session security, storage, and advanced workflows.
  </Card>
  <Card title="User Management" icon="users" href="/post-authentication/dashboard/introduction">
    Manage users through the SuperTokens Dashboard.
  </Card>
  <Card title="Deployment" icon="server" href="/deployment/self-host-supertokens">
    Run SuperTokens as a managed service or inside your infrastructure.
  </Card>
</CardGroup>
