File length: 49320 # Quickstart - Frontend Setup Source: https://supertokens.com/docs/quickstart/frontend-setup 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. ## 1. Install the SDK Run the following command in your terminal to install the package. ```bash npm i -s supertokens-auth-react ``` ```bash npm i -s supertokens-auth-react supertokens-web-js ``` ```bash yarn add supertokens-auth-react supertokens-web-js ``` ```bash pnpm add supertokens-auth-react supertokens-web-js ``` ```bash npm i -s supertokens-web-js ``` ```bash npm i -s supertokens-web-js ``` ```bash yarn add supertokens-web-js ``` ```bash pnpm add supertokens-web-js ``` ```bash npm i -s supertokens-web-js ``` ```bash npm i -s supertokens-web-js ``` ```bash yarn add supertokens-web-js ``` ```bash pnpm add supertokens-web-js ``` ## 2. Initialize the SDK In your main application file call the `SuperTokens.init` function to initialize the SDK. The `init` call includes the [main configuration details](/docs/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. ```tsx // highlight-start SuperTokens.init({ appInfo: { // learn more about this on https://supertokens.com/docs/references/frontend-sdks/reference#sdk-configuration appName: "", apiDomain: "", websiteDomain: "", apiBasePath: "", websiteBasePath: "", }, recipeList: [EmailPassword.init(), Session.init()], }); // highlight-end /* Your App */ class App extends React.Component { render() { return ( // highlight-next-line {/*Your app components*/} // highlight-next-line ); } } ``` 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 `*` route in the Angular app which renders our pre-built UI. which also needs to be initialised, but only on that route. **Creating the `` route** - Use the Angular CLI to generate a new route ```bash ng generate module auth --route auth --module app.module ``` - Add the following code to your `auth` angular component ```tsx title="/app/auth/auth.component.ts" @Component({ selector: "app-auth", template: '
', }) export class AuthComponent implements OnDestroy, AfterViewInit { constructor( private renderer: Renderer2, @Inject(DOCUMENT) private document: Document, ) {} ngAfterViewInit() { this.loadScript("^{prebuiltUIVersion}"); } 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({ appInfo: { appName: "", apiDomain: "", websiteDomain: "", apiBasePath: "", websiteBasePath: "", }, recipeList: [ supertokensUIEmailPassword.init(), supertokensUISession.init(), ], }); }; this.renderer.appendChild(this.document.body, script); } } ``` - In the `loadScript` function, we provide the SuperTokens config for the UI. We add the emailpassword and session recipe. - Initialize the `supertokens-web-js` SDK in your angular app's root component. This provides session management across your entire application. ```tsx title="/app/auth/auth.component.ts" @Component({ selector: "app-auth", template: '
', }) export class AuthComponent implements OnDestroy, AfterViewInit { constructor( private renderer: Renderer2, @Inject(DOCUMENT) private document: Document, ) {} ngAfterViewInit() { this.loadScript("^{prebuiltUIVersion}"); } 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({ appInfo: { appName: "", apiDomain: "", websiteDomain: "", apiBasePath: "", websiteBasePath: "", }, recipeList: [ supertokensUIEmailPassword.init(), supertokensUISession.init(), ], }); }; this.renderer.appendChild(this.document.body, script); } } ```
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 `*` route in the Vue app which renders our pre-built UI which also needs to be initialised, but only on that route. **Creating the `` route** - Create a new file `AuthView.vue`, this Vue component is used to render the auth component: ```tsx ``` - In the `loadScript` function, we provide the SuperTokens config for the UI. We add the emailpassword and session recipe. - Initialize the `supertokens-web-js` SDK in your Vue app's `main.ts` file. This provides session management across your entire application. ```tsx title="/main.ts " // @ts-ignore // @ts-ignore // @ts-ignore SuperTokens.init({ appInfo: { appName: "", apiDomain: "", apiBasePath: "", }, recipeList: [Session.init()], }); const app = createApp(App); app.use(router); app.mount("#app"); ```
## 3. Configure Routing 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. Call the `getSuperTokensRoutesForReactRouterDom` method from within any `react-router-dom` `Routes` component. ```tsx // highlight-next-line class App extends React.Component { render() { return ( {/*This renders the login UI on the route*/} // highlight-next-line {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [EmailPasswordPreBuiltUI])} {/*Your app routes*/} ); } } ``` :::important 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. ```tsx 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 ( ); } ``` ::: Add the highlighted code snippet to your root level `render` function. ```tsx class App extends React.Component { render() { // highlight-start if (canHandleRoute([EmailPasswordPreBuiltUI])) { // This renders the login UI on the route return getRoutingComponent([EmailPasswordPreBuiltUI]) } // highlight-end return ( {/*Your app*/} ); } } ``` Update your angular router so that all auth related requests load the `auth` component ```tsx title="/app/app-routing.module.ts" const routes: Routes = [ // highlight-start { path: "^{appInfo.websiteBasePath_withoutForwardSlash}", // @ts-ignore loadChildren: () => import("./auth/auth.module").then((m) => m.AuthModule), }, { path: "**", // @ts-ignore loadChildren: () => import("./home/home.module").then((m) => m.HomeModule), }, // highlight-end ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModule {} ``` Update your Vue router so that all auth related requests load the `AuthView` component ```tsx title="/router/index.ts" // @ts-ignore // @ts-ignore // @ts-ignore const router = createRouter({ // @ts-ignore history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: "/", name: "home", component: HomeView, }, { path: "/:pathMatch(.*)*", name: "auth", component: AuthView, }, ], }); export default router; ``` ## 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](/docs/post-authentication/session-management/switch-between-cookies-and-header-authentication). ## 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. You can wrap your components with the `` 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. ```tsx // highlight-next-line // @ts-ignore class App extends React.Component { render() { return ( {/*Components that require to be protected by authentication*/} // highlight-end } /> ); } } ``` You can use the `doesSessionExist` function to check if a session exists in all your routes. ```tsx async function doesSessionExist() { if (await Session.doesSessionExist()) { // user is logged in } else { // user has not logged in yet } } ``` You can use the `doesSessionExist` function to check if a session exists in all your routes. ```tsx async function doesSessionExist() { if (await Session.doesSessionExist()) { // user is logged in } else { // user has not logged in yet } } ``` ## 6. View the login UI You can check the login UI by visiting the `` route, in your frontend application. To review all the components of our pre-built UI please follow [this link](https://master--6571be2867f75556541fde98.chromatic.com/?path=/story/auth-page--playground).
## 1. Install the SDK Use the following command to install the required package. ```bash npm i -s supertokens-web-js ``` You need to add all of the following scripts to your app ```html ``` :::info If you want to implement a common authentication experience for both web and mobile, please look at our [**Unified Login guide**](/docs/authentication/unified-login/introduction). ::: ```bash npm i -s supertokens-react-native # IMPORTANT: If you already have @react-native-async-storage/async-storage as a dependency, make sure the version is 1.12.1 or higher npm i -s @react-native-async-storage/async-storage ``` Add to your `settings.gradle`: ```bash dependencyResolutionManagement { ... repositories { ... maven { url 'https://jitpack.io' } } } ``` Add the following to you app level's `build.gradle`: ```bash implementation 'com.github.supertokens:supertokens-android:X.Y.Z' ``` You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-android/releases) (ignore the `v` prefix in the releases). #### Using Cocoapods Add the Cocoapod dependency to your Podfile ```bash pod 'SuperTokensIOS' ``` #### 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 use the `master` branch after you enter the supertokens-ios repository URL: ```bash https://github.com/supertokens/supertokens-ios ``` Add the dependency to your pubspec.yaml ```bash supertokens_flutter: ^X.Y.Z ``` You can find the latest version of the SDK [here](https://github.com/supertokens/supertokens-flutter/releases) (ignore the `v` prefix in the releases). ## 2. Initialise SuperTokens Call the SDK init function at the start of your application. The invocation includes the [main configuration details](/docs/references/frontend-sdks/reference#sdk-configuration), as well as the **recipes** that you use in your setup. ```tsx SuperTokens.init({ appInfo: { apiDomain: "", apiBasePath: "", appName: "...", }, recipeList: [ Session.init(), EmailPassword.init(), ], }); ``` ```tsx supertokens.init({ appInfo: { apiDomain: "", apiBasePath: "", appName: "...", }, recipeList: [ supertokensSession.init(), supertokensEmailPassword.init(), ], }); ``` ```tsx SuperTokens.init({ apiDomain: "", apiBasePath: "", }); ``` Add the `SuperTokens.init` function call at the start of your application. ```kotlin ```swift ```dart void main() { SuperTokens.init( apiDomain: "", apiBasePath: "", ); } ``` ## 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. ### 3.1 Add the Sign Up form 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. ```tsx 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."); } } } ``` ```tsx async function signUpClicked(email: string, password: string) { try { let response = await supertokensEmailPassword.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 in 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."); } } } ``` 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. ```bash curl --location --request POST '/signup' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "formFields": [{ "id": "email", "value": "john@example.com" }, { "id": "password", "value": "somePassword123" }] }' ``` The response body from the API call has a `status` property in it: - `status: "OK"`: User creation was successful. The response also contains more information about the user, for example their user ID. - `status: "FIELD_ERROR"`: One of the form field inputs failed validation. The response body contains information about which form field input based on the `id`: - The email could fail validation if it's syntactically not an email, of it it's not unique. - The password could fail validation if it's not string enough (as defined by the backend password validator). Either way, you want to show the user an error next to the input form field. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend. - `status: "SIGN_UP_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that's in the response body contains a support code using which you can see why the sign up was not allowed. The `formFields` input is a key-value array. You must provide it an `email` and a `password` value at a minimum. If you want to provide additional items, for example the user's name or age, you can append it to the array like so: ```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. ```tsx 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."); } } } ``` ```tsx async function checkEmail(email: string) { try { let response = await supertokensEmailPassword.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 curl --location --request GET '/emailpassword/email/exists?email=john@example.com' ``` 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. ### 3.2 Add the Sign In Form 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. ```tsx 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."); } } } ``` ```tsx async function signInClicked(email: string, password: string) { try { let response = await supertokensEmailPassword.signIn({ 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). 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."); } } } ``` 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. ```bash curl --location --request POST '/signin' \ --header 'Content-Type: application/json; charset=utf-8' \ --data-raw '{ "formFields": [{ "id": "email", "value": "john@example.com" }, { "id": "password", "value": "somePassword123" }] }' ``` The response body from the API call has a `status` property in it: - `status: "OK"`: User sign in was successful. The response also contains more information about the user, for example their user ID. - `status: "WRONG_CREDENTIALS_ERROR"`: The input email and password combination is incorrect. - `status: "FIELD_ERROR"`: This indicates that the input email did not pass the backend validation - probably because it's syntactically not an email. You want to show the user an error next to the email input form field. - `status: "GENERAL_ERROR"`: This is only possible if you have overridden the backend API to send back a custom error message which should be displayed on the frontend. - `status: "SIGN_IN_NOT_ALLOWED"`: This can happen during automatic account linking or during MFA. The `reason` prop that's in the response body contains a support code using which you can see why the sign in was not allowed. On success, the backend sends back session tokens as part of the response headers which are automatically handled by our frontend SDK for you. ## 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 :::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. 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. ::: { return ( Are you using axios.create? ) }}> ```tsx // highlight-next-line let axiosInstance = axios.create({/*...*/}); // highlight-next-line SuperTokens.addAxiosInterceptors(axiosInstance); async function callAPI() { // use axios as you normally do let response = await axiosInstance.get("https://yourapi.com"); } ``` :::important You must call `addAxiosInterceptors` on all `axios` imports. ::: ```tsx // highlight-start SuperTokens.addAxiosInterceptors(axios); // highlight-end async function callAPI() { // use axios as you normally do let response = await axios.get("https://yourapi.com"); } ``` :::success When using `fetch`, network interceptors are added automatically when you call `supertokens.init`. So no action needed here. ::: ```kotlin ```dart // Import http from the SuperTokens package Future makeRequest() async { Uri uri = Uri.parse("http://localhost:3001/api"); var response = await http.get(uri); // handle response } ```

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. ```dart // Import http from the SuperTokens package Future makeRequest() async { Uri uri = Uri.parse("http://localhost:3001/api"); // Initialise your custom client var customClient = http.Client(); // provide your custom client to SuperTokens var httpClient = http.Client(client: customClient); var response = await httpClient.get(uri); // handle response } ```

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. ```dart void setup() { Dio dio = Dio(); // Create a Dio instance. dio.addSupertokensInterceptor(); } ```

Making network requests

You can make requests as you normally would with `dio`. ```dart void setup() { Dio dio = Dio( // Provide your config here ); dio.addSupertokensInterceptor(); var response = dio.get("http://localhost:3001/api"); // handle response } ```
:::note By default our mobile SDKs use a bearer token in the Authorization header to provide credentials. :::
### Without the Frontend SDK :::caution 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. #### 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 auth because you don't have access to the actual access token on the frontend (for security reasons), but may want to read its payload (for example to know the user's role). This token itself is not signed and hence can't be used in place of the access token itself. You may want to save this token in `localstorage` or in frontend cookies (using `document.cookies`). - `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. - You need to set the `credentials` header to `true` or `include`. This is achieved different based on the library you are using to make requests. 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 any of your API calls return with a status code of `401`, it means that the access token has expired. This requires you to refresh the session before retrying the same API call. You can call the refresh API as follows: ```bash curl --location --request POST '/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. ##### 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. You should save this in your application (e.g., in frontend `localstorage`). - `st-refresh-token`: This contains the current refresh token associated with the session. You should save this in your application (e.g., in frontend `localstorage`). #### When You Make Network Requests to Protected APIs You need to add the following headers to request: - `authorization: Bearer {access-token}` - You need to set the `credentials` to `true` or `include`. This is achieved different based on the library you are using to make requests. 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 any of your API calls return with a status code of `401`, it means that the access token has expired. This requires you to refresh the session before retrying the same API call. You can call the refresh API as follows: ```bash curl --location --request POST '/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. ## 5. Protect Frontend Routes You can use the `doesSessionExist` function to check if a session exists. ```tsx async function doesSessionExist() { if (await Session.doesSessionExist()) { // user is logged in } else { // user has not logged in yet } } ``` You can use the `doesSessionExist` function to check if a session exists. ```tsx async function doesSessionExist() { if (await Session.doesSessionExist()) { // user is logged in } else { // user has not logged in yet } } ``` You can use the `doesSessionExist` function to check if a session exists. ```tsx async function doesSessionExist() { if (await SuperTokens.doesSessionExist()) { // user is logged in } else { // user has not logged in yet } } ``` You can use the `doesSessionExist` function to check if a session exists. ```kotlin Future doesSessionExist() async { return await SuperTokens.doesSessionExist(); } ``` ## 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. ```tsx async function logout () { // highlight-next-line await Session.signOut(); window.location.href = "/auth"; // or to wherever your logic page is } ``` ```tsx async function logout () { // highlight-next-line await supertokensSession.signOut(); window.location.href = "/auth"; // or to wherever your logic page is } ``` ```tsx async function logout () { // highlight-next-line await SuperTokens.signOut(); // navigate to the login screen.. } ``` ```kotlin // navigate to the login screen.. } } ``` ```swift Future signOut() async { await SuperTokens.signOut( completionHandler: (error) { // handle error if any } ); } ``` - On success, the `signOut` function does not redirect the user to another page, so you must redirect the user yourself. - The `signOut` function calls the sign out API exposed by the session recipe on the backend. - If you call the `signOut` function whilst the access token has expired, but the refresh token still exists, our SDKs do an automatic session refresh before revoking the session.
:::success 🎉 Congratulations 🎉 Congratulations! You've successfully integrated your frontend app with SuperTokens. The [next section](./backend-setup) guides you through setting up your backend and then you should be able to complete a login flow. :::