diff --git a/v2/emailpassword/nextjs/app-directory/about.mdx b/v2/emailpassword/nextjs/app-directory/about.mdx
new file mode 100644
index 000000000..a82d63e1a
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/about.mdx
@@ -0,0 +1,65 @@
+---
+id: about
+title: About
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Adding a website page to display the auth related widgets (on `/auth` by default)
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend).
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+:::note
+This example app uses our pre built UI
+:::
+
+
+
+
+
diff --git a/v2/emailpassword/nextjs/app-directory/init.mdx b/v2/emailpassword/nextjs/app-directory/init.mdx
new file mode 100644
index 000000000..f9ce92ccd
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/init.mdx
@@ -0,0 +1,346 @@
+---
+id: init
+title: 1. Configuration
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import {Question, Answer}from "/src/components/question"
+import AppInfoForm from "/src/components/appInfoForm"
+import CoreInjector from "/src/components/coreInjector"
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+# 1. Configuration
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ websiteDomain: "^{form_websiteDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+ websiteBasePath: "^{form_websiteBasePath}"
+}
+
+```
+
+
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import EmailPasswordReact from 'supertokens-auth-react/recipe/emailpassword'
+import SessionReact from 'supertokens-auth-react/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import Router from 'next/navigation'
+import { useRouter } from "next/navigation";
+import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types'
+
+const routerInfo: { router?: ReturnType; pathName?: string } =
+ {};
+
+export function setRouter(
+ router: ReturnType,
+ pathName: string,
+) {
+ routerInfo.router = router;
+ routerInfo.pathName = pathName;
+}
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ EmailPasswordReact.init(),
+ SessionReact.init(),
+ ],
+ windowHandler: (original) => ({
+ ...original,
+ location: {
+ ...original.location,
+ getPathName: () => routerInfo.pathName!,
+ assign: (url) => routerInfo.router!.push(url.toString()),
+ setHref: (url) => routerInfo.router!.push(url.toString()),
+ },
+ }),
+ }
+}
+```
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import EmailPasswordWebJs from 'supertokens-web-js/recipe/emailpassword'
+import SessionWebJs from 'supertokens-web-js/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { SuperTokensConfig } from "supertokens-web-js/types"
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ EmailPasswordWebJs.init(),
+ SessionWebJs.init(),
+ ],
+ }
+}
+```
+
+
+
+
+
+## 5) Create a backend config function
+
+
+
+
+
+```tsx title="/config/backendConfig.ts"
+import SuperTokens from "supertokens-node";
+import EmailPasswordNode from 'supertokens-node/recipe/emailpassword'
+import SessionNode from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { TypeInput } from "supertokens-node/types";
+
+export const backendConfig = (): TypeInput => {
+ return {
+ framework: "express",
+ supertokens: {
+ ^{coreInjector_connection_uri_comment}
+ connectionURI: ^{coreInjector_uri}
+ ^{coreInjector_api_key_commented}apiKey: ^{coreInjector_api_key},
+ },
+ appInfo,
+ recipeList: [
+ EmailPasswordNode.init(),
+ SessionNode.init(),
+ ],
+ isInServerlessEnv: true,
+ }
+}
+
+let initialized = false;
+// This function is used in your APIs to make sure SuperTokens is initialised
+export function ensureSuperTokensInit() {
+ if (!initialized) {
+ SuperTokens.init(backendConfig());
+ initialized = true;
+ }
+}
+```
+
+`ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initiailised before using any functionality exposed by the backend SDKs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
+
+- Create a client component `/app/components/supertokensProvider.tsx`. This file will initialise SuperTokens and wrap its children with the `SuperTokensWrapper` component
+- Modify the `/app/layout.tsx` file to use the `SuperTokensProvider` component. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/layout.tsx)
+
+```tsx title="/app/components/supertokensProvider.tsx"
+'use client';
+declare let frontendConfig: any; // typecheck-only, removed from output
+declare let setRouter: any; // typecheck-only, removed from output
+import React from 'react';
+import { SuperTokensWrapper } from 'supertokens-auth-react';
+import SuperTokensReact from 'supertokens-auth-react';
+// @ts-ignore
+import { frontendConfig, setRouter } from '../config/frontend';
+import { usePathname, useRouter } from 'next/navigation';
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ SuperTokensReact.init(frontendConfig());
+}
+
+export const SuperTokensProvider: React.FC> = ({
+ children,
+}) => {
+ setRouter(useRouter(), usePathname() || window.location.pathname);
+
+ return {children};
+};
+```
+
+```tsx title="/app/layout.tsx"
+declare let SuperTokensProvider: any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { SuperTokensProvider } from "./components/supertokensProvider";
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions
+
+- Modify the `/app/layout.tsx` file to initialise the SuperTokens SDK. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+
+
+```tsx title="/app/layout.tsx"
+declare let frontendConfig: () => any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { frontendConfig } from '../config/frontend';
+import SuperTokensWebJs from 'supertokens-web-js'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ // highlight-next-line
+ SuperTokensWebJs.init(frontendConfig())
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2/emailpassword/nextjs/app-directory/next-steps.mdx b/v2/emailpassword/nextjs/app-directory/next-steps.mdx
new file mode 100644
index 000000000..b26f14fad
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/next-steps.mdx
@@ -0,0 +1,35 @@
+---
+id: next-steps
+title: 8. Next steps
+hide_title: true
+---
+
+
+
+
+import {Question, Answer}from "/src/components/question"
+
+# 6. Next steps
+
+## Setting up the core and database
+ {
+ return (
+ Are you using https://try.supertokens.com
as the connection URI in the init function?
+ )
+ }}>
+
+
+You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options:
+- [Managed service](../quick-setup/core/saas-setup)
+- Self hosted with your own database ([With Docker](../quick-setup/core/with-docker) or [Without Docker](../quick-setup/core/without-docker))
+
+
+
+
+:::success
+You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.
+:::
+
+
+
diff --git a/v2/emailpassword/nextjs/app-directory/protecting-route.mdx b/v2/emailpassword/nextjs/app-directory/protecting-route.mdx
new file mode 100644
index 000000000..19c693a80
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/protecting-route.mdx
@@ -0,0 +1,255 @@
+---
+id: protecting-route
+title: 5. Checking for sessions in frontend routes
+hide_title: true
+---
+
+
+
+
+# 5. Checking for sessions in frontend routes
+
+Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page.
+
+## Sessions with Client Components
+
+Lets create a client component for the `/` route of our website.
+
+### Using the `SessionAuth` wrapper component
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ return (
+
+
+ Hello world
+
+
+ );
+}
+```
+
+`SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page.
+
+:::caution
+At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.
+
+Refer to the next section of this page to learn how to use sessions on the server side.
+:::
+
+### Using `useSessionContext`
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { useSessionContext } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ const session = useSessionContext();
+
+ if (session.loading) {
+ return
Loading...
;
+ }
+
+ if (session.doesSessionExist === false) {
+ return Session does not exist
;
+ }
+
+ return (
+
+
+
+ Client side component got userId: {session.userId}
+
+
+
+ );
+}
+```
+
+`useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly.
+
+:::info
+`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.
+:::
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+## Sessions with Server Components
+
+### Creating some helper Components
+
+#### Creating a wrapper around `SessionAuth`
+Let's say we want to protect the home page of your website (`/` route). First we will create a wrapper around the `SessionAuth` component provided by SuperTokens to allow us to use it on both server side and client side.
+
+```tsx title="app/components/sessionAuthForNextJS.tsx"
+"use client";
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+
+type Props = Parameters[0] & {
+ children?: React.ReactNode | undefined;
+};
+
+export const SessionAuthForNextJS = (props: Props) => {
+ if (typeof window === "undefined") {
+ return props.children;
+ }
+
+ return {props.children};
+};
+```
+
+This is a client component that renders just its children on the server side and renders the children wrapped with `SessionAuth` on the client side.
+
+#### Creating the `TryRefreshComponent`
+
+This component will refresh the user's session if their current session has expired.
+
+```tsx title="app/components/tryRefreshClientComponent.tsx"
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Session from "supertokens-auth-react/recipe/session";
+import SuperTokens from "supertokens-auth-react";
+
+export const TryRefreshComponent = () => {
+ const router = useRouter();
+ const [didError, setDidError] = useState(false);
+
+ useEffect(() => {
+ /**
+ * `attemptRefreshingSession` will call the refresh token endpoint to try and
+ * refresh the session. This will throw an error if the session cannot be refreshed.
+ */
+ void Session.attemptRefreshingSession()
+ .then((hasSession) => {
+ /**
+ * If the user has a valid session, we reload the page to restart the flow
+ * with valid session tokens
+ */
+ if (hasSession) {
+ router.refresh();
+ } else {
+ SuperTokens.redirectToAuth();
+ }
+ })
+ .catch(() => {
+ setDidError(true);
+ });
+ }, []);
+
+ /**
+ * We add this check to make sure we handle the case where the refresh API fails with
+ * an unexpected error
+ */
+ if (didError) {
+ return Something went wrong, please reload the page
;
+ }
+
+ return Loading...
;
+};
+```
+
+### Using `SessionAuthForNextJS` and checking for sessions
+
+We then create a server component that can check if the session exists and return any session information we may need:
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ // `session` will be undefined if it does not exist or has expired
+ if (!session) {
+ if (!hasToken) {
+ /**
+ * This means that the user is not logged in. If you want to display some other UI in this
+ * case, you can do so here.
+ */
+ return redirect("/auth");
+ }
+
+ /**
+ * `hasInvalidClaims` indicates that session claims did not pass validation. For example if email
+ * verification is required but the user's email has not been verified.
+ */
+ if (hasInvalidClaims) {
+ /**
+ * This will make sure that the user is redirected based on their session claims. For example they
+ * will be redirected to the email verification screen if needed.
+ *
+ * We pass in no children in this case to prevent hydration issues and still be able to redirect the
+ * user.
+ */
+ return ;
+ } else {
+ /**
+ * This means that the session does not exist but we have session tokens for the user. In this case
+ * the `TryRefreshComponent` will try to refresh the session.
+ */
+ return ;
+ }
+ }
+
+ /**
+ * SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
+ * It will redirect to the login page if the session does not exist etc.
+ */
+ return (
+
+
+ Your user id is: {session.getUserId()}
+
+
+ );
+}
+```
+
+`getSSRSession` is a utility function we created in the [previous step](./session-helpers.mdx). The `TryRefreshComponent` is a client component that checks if a session exists and tries to refresh the session if it is expired.
+
+And then we can modify the `/app/page.tsx` file to use our server component
+
+```tsx title="app/page.tsx"
+declare let HomePage: any; // typecheck-only, removed from output
+import styles from './page.module.css'
+// @ts-ignore
+import { HomePage } from "./components/home";
+
+export default function Home() {
+ return (
+
+
+
+ )
+}
+```
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+:::important
+An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx).
+:::
diff --git a/v2/emailpassword/nextjs/app-directory/server-components-requests.mdx b/v2/emailpassword/nextjs/app-directory/server-components-requests.mdx
new file mode 100644
index 000000000..536a7e39e
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/server-components-requests.mdx
@@ -0,0 +1,83 @@
+---
+id: server-components-requests
+title: 7. Making requests from Server Components
+hide_title: true
+---
+
+
+
+
+# 7. Making requests from Server Components
+
+Lets modify the Home page we made in a [previous step](../protecting-route.mdx) to make a call to this API
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ if (!session) {
+ if (!hasToken) {
+ return redirect("/auth");
+ }
+
+ if (hasInvalidClaims) {
+ return ;
+ } else {
+ return ;
+ }
+ }
+
+ // highlight-start
+ const userInfoResponse = await fetch('http://localhost:3000/api/user', {
+ headers: {
+ /**
+ * We read the access token from the session and use that as a Bearer token when
+ * making network requests.
+ */
+ Authorization: 'Bearer ' + session.getAccessToken(),
+ },
+ });
+
+ let message = "";
+
+ if (userInfoResponse.status === 200) {
+ message = `Your user id is: ${session.getUserId()}`
+ } else if (userInfoResponse.status === 500) {
+ message = "Something went wrong"
+ } else if (userInfoResponse.status === 401) {
+ // The TryRefreshComponent will try to refresh the session
+ return
+ } else if (userInfoResponse.status === 403) {
+ // SessionAuthForNextJS will redirect based on which claim is invalid
+ return ;
+ }
+
+ // You can use `userInfoResponse` to read the users session information
+ // highlight-end
+
+ return (
+
+
+ {message}
+
+
+ );
+}
+```
+
+We use `session` returned by `getSSRSession` to get the access token of the user. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the information. You can use the `session` object to fetch other information such as `session.getUserId()`.
diff --git a/v2/emailpassword/nextjs/app-directory/session-helpers.mdx b/v2/emailpassword/nextjs/app-directory/session-helpers.mdx
new file mode 100644
index 000000000..f168b0b6a
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/session-helpers.mdx
@@ -0,0 +1,166 @@
+---
+id: session-helpers
+title: 4. Add helper functions for sessions
+hide_title: true
+---
+
+
+
+
+# 4. Add helper functions for sessions
+
+To make it easy to access session information and protect our API routes we will create some helper functions:
+
+```ts title="app/sessionUtils.ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { serialize } from "cookie";
+import { cookies, headers } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+import Session, { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";
+import { PreParsedRequest, CollectingResponse } from "supertokens-node/framework/custom";
+import { HTTPMethod } from "supertokens-node/types";
+// @ts-ignore
+import { ensureSuperTokensInit } from "./config/backend";
+
+ensureSuperTokensInit();
+
+export async function getSSRSession(
+ req?: NextRequest,
+ options?: VerifySessionOptions
+): Promise<{
+ session: SessionContainer | undefined;
+ hasToken: boolean;
+ hasInvalidClaims: boolean;
+ baseResponse: CollectingResponse;
+ nextResponse?: NextResponse;
+}> {
+ const query = req !== undefined ? Object.fromEntries(new URL(req.url).searchParams.entries()) : {};
+ const parsedCookies: Record = Object.fromEntries(
+ (req !== undefined ? req.cookies : cookies()).getAll().map((cookie) => [cookie.name, cookie.value])
+ );
+
+ /**
+ * Pre parsed request is a wrapper exposed by SuperTokens. It is used as a helper to detect if the
+ * original request contains session tokens. We then use this pre parsed request to call `getSession`
+ * to check if there is a valid session.
+ */
+ let baseRequest = new PreParsedRequest({
+ method: req !== undefined ? (req.method as HTTPMethod) : "get",
+ url: req !== undefined ? req.url : "",
+ query: query,
+ headers: req !== undefined ? req.headers : headers(),
+ cookies: parsedCookies,
+ getFormBody: () => req!.formData(),
+ getJSONBody: () => req!.json(),
+ });
+
+ /**
+ * Collecting response is a wrapper exposed by SuperTokens. In this case we are using an empty
+ * CollectingResponse when calling `getSession`. If the request contains valid session tokens
+ * the SuperTokens SDK will attach all the relevant tokens to the collecting response object which
+ * we can then use to return those session tokens in the final result (refer to `withSession` in this file)
+ */
+ let baseResponse = new CollectingResponse();
+
+ try {
+ /**
+ * `getSession` will throw if session is required and there is no valid session. You can use
+ * `options` to configure whether or not you want to require sessions when calling `getSSRSession`
+ */
+ let session = await Session.getSession(baseRequest, baseResponse, options);
+ return {
+ session,
+ hasInvalidClaims: false,
+ hasToken: session !== undefined,
+ baseResponse,
+ };
+ } catch (err) {
+ if (Session.Error.isErrorFromSuperTokens(err)) {
+ return {
+ hasToken: err.type !== Session.Error.UNAUTHORISED,
+ /**
+ * This allows us to protect our routes based on the current session claims. For example
+ * this will be true if email verification is required but the user has not verified their
+ * email.
+ */
+ hasInvalidClaims: err.type === Session.Error.INVALID_CLAIMS,
+ session: undefined,
+ baseResponse,
+ nextResponse: new NextResponse("Authentication required", {
+ status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
+ }),
+ };
+ } else {
+ throw err;
+ }
+ }
+}
+
+export async function withSession(
+ request: NextRequest,
+ handler: (session: SessionContainer | undefined) => Promise,
+ options?: VerifySessionOptions
+) {
+ let { session, nextResponse, baseResponse } = await getSSRSession(request, options);
+ if (nextResponse) {
+ return nextResponse;
+ }
+
+ let userResponse = await handler(session);
+
+ let didAddCookies = false;
+ let didAddHeaders = false;
+
+ /**
+ * Base response is the response from SuperTokens that contains all the session tokens.
+ * We add all cookies and headers in the base response to the final response from the
+ * API to make sure sessions work correctly.
+ */
+ for (const respCookie of baseResponse.cookies) {
+ didAddCookies = true;
+ userResponse.headers.append(
+ "Set-Cookie",
+ serialize(respCookie.key, respCookie.value, {
+ domain: respCookie.domain,
+ expires: new Date(respCookie.expires),
+ httpOnly: respCookie.httpOnly,
+ path: respCookie.path,
+ sameSite: respCookie.sameSite,
+ secure: respCookie.secure,
+ })
+ );
+ }
+
+ baseResponse.headers.forEach((value, key) => {
+ didAddHeaders = true;
+ userResponse.headers.set(key, value);
+ });
+
+ /**
+ * For some deployment services (Vercel for example) production builds can return cached results for
+ * APIs with older header values. In this case if the session tokens have changed (because of refreshing
+ * for example) the cached result would still contain the older tokens and sessions would stop working.
+ *
+ * As a result, if we add cookies or headers from base response we also set the Cache-Control header
+ * to make sure that the final result is not a cached version.
+ */
+ if (didAddCookies || didAddHeaders) {
+ if (!userResponse.headers.has("Cache-Control")) {
+ // This is needed for production deployments with Vercel
+ userResponse.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+ }
+
+ return userResponse;
+}
+```
+
+- `getSSRSession` will be used in our frontend routes to get session information when rendering on the server side. This function will:
+ - `{..., session: Object, hasToken: true}` if a session exists
+ - `{..., session: undefined, hasToken: false}` if a session does not exist
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: false}` if the session is expired
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: true}` If the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
+
+- `withSession` will be used as a session guard for each of our API routes. If a session exists it will be passed to the callback, which is where we will write our API logic. If no session exists it will pass `undefined` to the callback. This function will:
+ - Return status `401` if the session has expired
+ - Return status `403` if the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
diff --git a/v2/emailpassword/nextjs/app-directory/session-verification-middleware.mdx b/v2/emailpassword/nextjs/app-directory/session-verification-middleware.mdx
new file mode 100644
index 000000000..967c12710
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/session-verification-middleware.mdx
@@ -0,0 +1,89 @@
+---
+id: session-verification-middleware
+title: Using the Next.js middleware
+hide_title: true
+---
+
+
+
+
+# Using the Next.js middleware
+
+:::important
+This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step.
+:::
+
+## Setting up the middleware
+
+In the middleware we check if a session exists using the `withSession` helper function we created [here](./session-helpers.mdx) and set the user's user id to the request headers using the session object. You can set other information in the same way.
+
+:::caution
+You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx).
+:::
+
+```tsx title="middleware.tsx"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse } from 'next/server'
+import type { NextRequest } from 'next/server'
+import { SessionContainer } from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { withSession } from './app/sessionUtils';
+
+
+export async function middleware(
+ request: NextRequest & { session?: SessionContainer }
+) {
+ if (request.headers.has("x-user-id")) {
+ console.warn("The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.");
+ request.headers.delete("x-user-id");
+ }
+
+ if (request.nextUrl.pathname.startsWith('/api/auth')) {
+ /**
+ * /api/auth/* endpoints are exposed by the SuperTokens SDK,
+ * we do not want to modify the request for these routes
+ */
+ return NextResponse.next()
+ }
+
+ return withSession(request, async (session) => {
+ if (session === undefined) {
+ return NextResponse.next()
+ }
+ return NextResponse.next({
+ headers: {
+ // You cannot attach the full session object here
+ 'x-user-id': session.getUserId(),
+ },
+ })
+ })
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+## Fetching the user ID in your APIs
+
+The middleware will run for all routes, we can read information set by the middleware in the API routes:
+
+```tsx title="app/api/userid/route.ts"
+import { NextResponse, NextRequest } from "next/server";
+
+export function GET(request: NextRequest) {
+ const userId = request.headers.get("x-user-id");
+
+ // The middleware only adds the userId if a session exists
+ if (userId === null) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ userId,
+ });
+}
+```
+
+This creates a `GET` request for the `/api/userid` route which returns the user id of the currently logged in user.
diff --git a/v2/emailpassword/nextjs/app-directory/session-verification-session-guard.mdx b/v2/emailpassword/nextjs/app-directory/session-verification-session-guard.mdx
new file mode 100644
index 000000000..5b64f688a
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/session-verification-session-guard.mdx
@@ -0,0 +1,50 @@
+---
+id: session-verification-session-guard
+title: Adding a session guard to each API route
+hide_title: true
+---
+
+
+
+
+# Adding a session guard to each API route
+
+:::note
+This is applicable for when the frontend calls an API in the `/app/api` folder.
+:::
+
+For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
+
+Create a new file `/app/api/user/route.ts`
+
+- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/api/user/route.ts).
+
+```ts title="app/api/user/route.ts"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse, NextRequest } from "next/server";
+import SuperTokens from "supertokens-node";
+// @ts-ignore
+import { withSession } from "../../sessionUtils";
+
+export function GET(request: NextRequest) {
+ return withSession(request, async (session) => {
+ if (!session) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ note: "Fetch any data from your application for authenticated user after using verifySession middleware",
+ userId: session.getUserId(),
+ sessionHandle: session.getHandle(),
+ accessTokenPayload: session.getAccessTokenPayload(),
+ });
+ });
+}
+```
+
+In the above snippet we are creating a `GET` handler for the `/api/user` route. We call the `withSession` helper function we created in a [previous step](./session-helpers.mdx), the function will pass the session object in the callback which we then use to read user information. If a session does not exist `undefined` will be passed intead.
+
+The `withSession` guard will return:
+- Status `401` if the session does not exist or has expired
+- Stauts `403` if the session claims fail their validation. For example if email verification is required but the user's email is not verified.
diff --git a/v2/emailpassword/nextjs/app-directory/setting-up-backend.mdx b/v2/emailpassword/nextjs/app-directory/setting-up-backend.mdx
new file mode 100644
index 000000000..6beea3b80
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/setting-up-backend.mdx
@@ -0,0 +1,82 @@
+---
+id: setting-up-backend
+title: 3. Adding auth APIs
+hide_title: true
+---
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import AppInfoForm from "/src/components/appInfoForm"
+
+# 3. Adding auth APIs
+
+We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`.
+
+## 1) Create the API folder
+- Be sure to create the `auth` folder in the `app/api/` folder.
+- `[[...path]].tsx` will use the `getAppDirRequestHandler` helper function exposed by `supertokens-node` which helps in calling all the APIs like sign in, sign up etc. (the full folder path should be `/app/api/auth/[[...path]].tsx`).
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/api/auth/%5B...path%5D).
+
+## 2) Expose the SuperTokens APIs
+
+
+
+```tsx title="app/api/auth/[[...path]].ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { getAppDirRequestHandler } from 'supertokens-node/nextjs';
+import { NextRequest, NextResponse } from 'next/server';
+// @ts-ignore
+import { ensureSuperTokensInit } from '../../../config/backend';
+
+ensureSuperTokensInit();
+
+const handleCall = getAppDirRequestHandler(NextResponse);
+
+export async function GET(request: NextRequest) {
+ const res = await handleCall(request);
+ if (!res.headers.has('Cache-Control')) {
+ // This is needed for production deployments with Vercel
+ res.headers.set(
+ 'Cache-Control',
+ 'no-cache, no-store, max-age=0, must-revalidate'
+ )
+ }
+ return res;
+}
+
+export async function POST(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function DELETE(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PUT(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PATCH(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function HEAD(request: NextRequest) {
+ return handleCall(request);
+}
+```
+
+:::note
+In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.
+:::
+
+
+
+## 3) Use the login widget
+If you are now able to sign in or sign up, this means the backend setup is done correctly! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
diff --git a/v2/emailpassword/nextjs/app-directory/setting-up-frontend.mdx b/v2/emailpassword/nextjs/app-directory/setting-up-frontend.mdx
new file mode 100644
index 000000000..635a11d76
--- /dev/null
+++ b/v2/emailpassword/nextjs/app-directory/setting-up-frontend.mdx
@@ -0,0 +1,72 @@
+---
+id: setting-up-frontend
+title: 2. Showing the Login UI
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {
+ PreBuiltOrCustomUISwitcher,
+ PreBuiltUIContent,
+ CustomUIContent,
+} from "/src/components/preBuiltOrCustomUISwitcher";
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import AppInfoForm from "/src/components/appInfoForm";
+
+# 2. Showing the Login UI
+
+
+
+
+
+## 1) Create the `app/auth/[[...path]].tsx` page
+- Be sure to create the `auth` folder in the `app` folder.
+- `[[...path]].tsx` will contain the component for showing SuperTokens UI
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/auth/%5B%5B...path%5D%5D).
+
+## 2) Create the `Auth` component:
+
+```tsx title="app/auth/[[...path]].tsx"
+'use client';
+
+import { useEffect } from 'react';
+import { redirectToAuth } from 'supertokens-auth-react';
+import SuperTokens from 'supertokens-auth-react/ui';
+import { ^{recipePreBuiltUINameCapitalLetters} } from "supertokens-auth-react/recipe/^{codeImportRecipeName}/prebuiltui";
+
+export default function Auth() {
+ // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
+ useEffect(() => {
+ if (
+ SuperTokens.canHandleRoute([^{recipePreBuiltUINameCapitalLetters}]) === false
+ ) {
+ redirectToAuth({ redirectBack: false });
+ }
+ }, []);
+
+ if (typeof window !== 'undefined') {
+ return SuperTokens.getRoutingComponent([^{recipePreBuiltUINameCapitalLetters}]);
+ }
+
+ return null;
+}
+```
+
+## 3) Visit `/auth` page on your website
+
+If you see a login UI, then you have successfully completed this step! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
+
+
+
+
+
+You need to build your own UI. Please follow the docs after the "Initialisation" section in the "Using your own UI" section for how to build out the various auth flows.
+
+
+
+
diff --git a/v2/emailpassword/nextjs/init.mdx b/v2/emailpassword/nextjs/init.mdx
index 315b6e469..d6c24d92a 100644
--- a/v2/emailpassword/nextjs/init.mdx
+++ b/v2/emailpassword/nextjs/init.mdx
@@ -31,7 +31,6 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
- Create an `appInfo.ts` inside the `config` folder.
- Create a `backendConfig.ts` inside the `config` folder.
- Create a `frontendConfig.ts` inside the `config` folder.
-- An example of these files can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/config/).
## 3) Create the `appInfo` configuration.
@@ -207,7 +206,6 @@ export const backendConfig = (): TypeInput => {
## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
- Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app).
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx)
```tsx title="/pages/_app.tsx"
diff --git a/v2/emailpassword/nextjs/protecting-route.mdx b/v2/emailpassword/nextjs/protecting-route.mdx
index 03e6187c7..21505368e 100644
--- a/v2/emailpassword/nextjs/protecting-route.mdx
+++ b/v2/emailpassword/nextjs/protecting-route.mdx
@@ -38,10 +38,6 @@ export default function Home() {
}
```
-:::important
-An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L36).
-:::
-
:::tip Test by navigating to `/`
You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
:::
diff --git a/v2/emailpassword/nextjs/session-verification/in-api.mdx b/v2/emailpassword/nextjs/session-verification/in-api.mdx
index a8220ae96..e0d57c781 100644
--- a/v2/emailpassword/nextjs/session-verification/in-api.mdx
+++ b/v2/emailpassword/nextjs/session-verification/in-api.mdx
@@ -18,7 +18,6 @@ This is applicable for when the frontend calls an API in the `/pages/api` folder
For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
## 1) Create a new file `/pages/api/user.ts`
-- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/user.ts).
## 2) Call the `supertokens.init` function
Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file.
diff --git a/v2/emailpassword/nextjs/session-verification/in-ssr.mdx b/v2/emailpassword/nextjs/session-verification/in-ssr.mdx
index e33b15cf2..4e7a8cdb0 100644
--- a/v2/emailpassword/nextjs/session-verification/in-ssr.mdx
+++ b/v2/emailpassword/nextjs/session-verification/in-ssr.mdx
@@ -24,8 +24,6 @@ For this guide, we will assume that we want to pass the logged in user's ID as a
If using `getInitialProps`, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
:::
-An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L15).
-
```tsx
import Session from 'supertokens-node/recipe/session'
@@ -90,7 +88,6 @@ Do not use the `verifySession` function here. The reason is that this will send
- The following will refresh a session if needed, for all your website pages
- This goes in the `/pages/_app.tsx` file
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx#L16).
```tsx title="/pages/_app.tsx"
diff --git a/v2/emailpassword/nextjs/setting-up-backend.mdx b/v2/emailpassword/nextjs/setting-up-backend.mdx
index 89c0d6321..3658e19f8 100644
--- a/v2/emailpassword/nextjs/setting-up-backend.mdx
+++ b/v2/emailpassword/nextjs/setting-up-backend.mdx
@@ -18,7 +18,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by
## 1) Create the `pages/api/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages/api/` folder.
- `[[...path]].tsx` will use the middleware exposed by `supertokens-node` which exposes all the APIs like sign in, sign up etc..
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/auth/%5B%5B...path%5D%5D.ts).
## 2) Expose the SuperTokens APIs
diff --git a/v2/emailpassword/nextjs/setting-up-frontend.mdx b/v2/emailpassword/nextjs/setting-up-frontend.mdx
index f1ff8f414..9f7cf1295 100644
--- a/v2/emailpassword/nextjs/setting-up-frontend.mdx
+++ b/v2/emailpassword/nextjs/setting-up-frontend.mdx
@@ -27,7 +27,6 @@ import AppInfoForm from "/src/components/appInfoForm";
## 1) Create the `pages/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages` folder.
- `[[...path]].tsx` will contain the component for showing SuperTokens UI
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/auth/%5B%5B...path%5D%5D.tsx).
## 2) Create the `Auth` component:
diff --git a/v2/emailpassword/sidebars.js b/v2/emailpassword/sidebars.js
index 956c32813..d86d0c7b8 100644
--- a/v2/emailpassword/sidebars.js
+++ b/v2/emailpassword/sidebars.js
@@ -176,20 +176,48 @@ module.exports = {
logoUrl: '/img/logos/next-logo.png'
},
items: [
- "nextjs/about",
- "nextjs/init",
- "nextjs/setting-up-frontend",
- "nextjs/setting-up-backend",
- "nextjs/protecting-route",
{
type: 'category',
- label: '5. Session verification',
+ label: 'Using the App directory',
items: [
- "nextjs/session-verification/in-api",
- "nextjs/session-verification/in-ssr"
+ "nextjs/app-directory/about",
+ "nextjs/app-directory/init",
+ "nextjs/app-directory/setting-up-frontend",
+ "nextjs/app-directory/setting-up-backend",
+ "nextjs/app-directory/session-helpers",
+ "nextjs/app-directory/protecting-route",
+ {
+ type: "category",
+ label: "6. Checking for sessions in API routes",
+ items: [
+ "nextjs/app-directory/session-verification-session-guard",
+ "nextjs/app-directory/session-verification-middleware",
+ ],
+ },
+ "nextjs/app-directory/server-components-requests",
+ "nextjs/app-directory/next-steps"
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Using the Pages directory',
+ items: [
+ "nextjs/about",
+ "nextjs/init",
+ "nextjs/setting-up-frontend",
+ "nextjs/setting-up-backend",
+ "nextjs/protecting-route",
+ {
+ type: 'category',
+ label: '5. Session verification',
+ items: [
+ "nextjs/session-verification/in-api",
+ "nextjs/session-verification/in-ssr"
+ ],
+ },
+ "nextjs/next-steps"
],
},
- "nextjs/next-steps"
],
},
{
diff --git a/v2/passwordless/nextjs/app-directory/about.mdx b/v2/passwordless/nextjs/app-directory/about.mdx
new file mode 100644
index 000000000..a82d63e1a
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/about.mdx
@@ -0,0 +1,65 @@
+---
+id: about
+title: About
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Adding a website page to display the auth related widgets (on `/auth` by default)
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend).
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+:::note
+This example app uses our pre built UI
+:::
+
+
+
+
+
diff --git a/v2/passwordless/nextjs/app-directory/init.mdx b/v2/passwordless/nextjs/app-directory/init.mdx
new file mode 100644
index 000000000..9ff045085
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/init.mdx
@@ -0,0 +1,357 @@
+---
+id: init
+title: 1. Configuration
+hide_title: true
+show_ui_switcher: true
+---
+
+import { PasswordlessFrontendForm } from "/src/components/snippetConfigForm/passwordlessFrontendForm";
+import { PasswordlessBackendForm } from "/src/components/snippetConfigForm/passwordlessBackendForm";
+import BackendDeliveryMethod from "../../reusableMD/backendDeliveryMethod.mdx"
+
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import {Question, Answer}from "/src/components/question"
+import AppInfoForm from "/src/components/appInfoForm"
+import CoreInjector from "/src/components/coreInjector"
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+# 1. Configuration
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ websiteDomain: "^{form_websiteDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+ websiteBasePath: "^{form_websiteBasePath}"
+}
+
+```
+
+
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import PasswordlessReact from 'supertokens-auth-react/recipe/passwordless'
+import SessionReact from 'supertokens-auth-react/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import Router from 'next/navigation'
+import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types'
+import { useRouter } from "next/navigation";
+
+const routerInfo: { router?: ReturnType; pathName?: string } =
+ {};
+
+export function setRouter(
+ router: ReturnType,
+ pathName: string,
+) {
+ routerInfo.router = router;
+ routerInfo.pathName = pathName;
+}
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ PasswordlessReact.init({
+ contactMethod: "^{form_contactMethod}"
+ }),
+ SessionReact.init(),
+ ],
+ windowHandler: (original) => ({
+ ...original,
+ location: {
+ ...original.location,
+ getPathName: () => routerInfo.pathName!,
+ assign: (url) => routerInfo.router!.push(url.toString()),
+ setHref: (url) => routerInfo.router!.push(url.toString()),
+ },
+ }),
+ }
+}
+```
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import PasswordlessWebJs from 'supertokens-web-js/recipe/passwordless'
+import SessionWebJs from 'supertokens-web-js/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { SuperTokensConfig } from "supertokens-web-js/types"
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ PasswordlessWebJs.init(),
+ SessionWebJs.init(),
+ ],
+ }
+}
+```
+
+
+
+
+
+## 5) Create a backend config function
+
+
+
+
+
+
+```tsx title="/config/backendConfig.ts"
+import SuperTokens from "supertokens-node";
+import PasswordlessNode from 'supertokens-node/recipe/passwordless'
+import SessionNode from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { TypeInput } from "supertokens-node/types";
+
+export const backendConfig = (): TypeInput => {
+ return {
+ framework: "express",
+ supertokens: {
+ ^{coreInjector_connection_uri_comment}
+ connectionURI: ^{coreInjector_uri}
+ ^{coreInjector_api_key_commented}apiKey: ^{coreInjector_api_key},
+ },
+ appInfo,
+ recipeList: [
+ PasswordlessNode.init({
+ flowType: "^{form_flowType}",
+ contactMethod: "^{form_contactMethod}"
+ }),
+ SessionNode.init(),
+ ],
+ isInServerlessEnv: true,
+ }
+}
+
+let initialized = false;
+// This function is used in your APIs to make sure SuperTokens is initialised
+export function ensureSuperTokensInit() {
+ if (!initialized) {
+ SuperTokens.init(backendConfig());
+ initialized = true;
+ }
+}
+```
+
+`ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initiailised before using any functionality exposed by the backend SDKs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
+
+- Create a client component `/app/components/supertokensProvider.tsx`. This file will initialise SuperTokens and wrap its children with the `SuperTokensWrapper` component
+- Modify the `/app/layout.tsx` file to use the `SuperTokensProvider` component. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/layout.tsx)
+
+```tsx title="/app/components/supertokensProvider.tsx"
+'use client';
+declare let frontendConfig: any; // typecheck-only, removed from output
+declare let setRouter: any; // typecheck-only, removed from output
+import React from 'react';
+import { SuperTokensWrapper } from 'supertokens-auth-react';
+import SuperTokensReact from 'supertokens-auth-react';
+// @ts-ignore
+import { frontendConfig, setRouter } from '../config/frontend';
+import { usePathname, useRouter } from 'next/navigation';
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ SuperTokensReact.init(frontendConfig());
+}
+
+export const SuperTokensProvider: React.FC> = ({
+ children,
+}) => {
+ setRouter(useRouter(), usePathname() || window.location.pathname);
+
+ return {children};
+};
+```
+
+```tsx title="/app/layout.tsx"
+declare let SuperTokensProvider: any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { SuperTokensProvider } from "./components/supertokensProvider";
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions
+
+- Modify the `/app/layout.tsx` file to initialise the SuperTokens SDK. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+
+
+```tsx title="/app/layout.tsx"
+declare let frontendConfig: () => any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { frontendConfig } from '../config/frontend';
+import SuperTokensWebJs from 'supertokens-web-js'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ // highlight-next-line
+ SuperTokensWebJs.init(frontendConfig())
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2/passwordless/nextjs/app-directory/next-steps.mdx b/v2/passwordless/nextjs/app-directory/next-steps.mdx
new file mode 100644
index 000000000..b26f14fad
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/next-steps.mdx
@@ -0,0 +1,35 @@
+---
+id: next-steps
+title: 8. Next steps
+hide_title: true
+---
+
+
+
+
+import {Question, Answer}from "/src/components/question"
+
+# 6. Next steps
+
+## Setting up the core and database
+ {
+ return (
+ Are you using https://try.supertokens.com
as the connection URI in the init function?
+ )
+ }}>
+
+
+You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options:
+- [Managed service](../quick-setup/core/saas-setup)
+- Self hosted with your own database ([With Docker](../quick-setup/core/with-docker) or [Without Docker](../quick-setup/core/without-docker))
+
+
+
+
+:::success
+You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.
+:::
+
+
+
diff --git a/v2/passwordless/nextjs/app-directory/protecting-route.mdx b/v2/passwordless/nextjs/app-directory/protecting-route.mdx
new file mode 100644
index 000000000..19c693a80
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/protecting-route.mdx
@@ -0,0 +1,255 @@
+---
+id: protecting-route
+title: 5. Checking for sessions in frontend routes
+hide_title: true
+---
+
+
+
+
+# 5. Checking for sessions in frontend routes
+
+Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page.
+
+## Sessions with Client Components
+
+Lets create a client component for the `/` route of our website.
+
+### Using the `SessionAuth` wrapper component
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ return (
+
+
+ Hello world
+
+
+ );
+}
+```
+
+`SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page.
+
+:::caution
+At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.
+
+Refer to the next section of this page to learn how to use sessions on the server side.
+:::
+
+### Using `useSessionContext`
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { useSessionContext } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ const session = useSessionContext();
+
+ if (session.loading) {
+ return Loading...
;
+ }
+
+ if (session.doesSessionExist === false) {
+ return Session does not exist
;
+ }
+
+ return (
+
+
+
+ Client side component got userId: {session.userId}
+
+
+
+ );
+}
+```
+
+`useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly.
+
+:::info
+`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.
+:::
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+## Sessions with Server Components
+
+### Creating some helper Components
+
+#### Creating a wrapper around `SessionAuth`
+Let's say we want to protect the home page of your website (`/` route). First we will create a wrapper around the `SessionAuth` component provided by SuperTokens to allow us to use it on both server side and client side.
+
+```tsx title="app/components/sessionAuthForNextJS.tsx"
+"use client";
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+
+type Props = Parameters[0] & {
+ children?: React.ReactNode | undefined;
+};
+
+export const SessionAuthForNextJS = (props: Props) => {
+ if (typeof window === "undefined") {
+ return props.children;
+ }
+
+ return {props.children};
+};
+```
+
+This is a client component that renders just its children on the server side and renders the children wrapped with `SessionAuth` on the client side.
+
+#### Creating the `TryRefreshComponent`
+
+This component will refresh the user's session if their current session has expired.
+
+```tsx title="app/components/tryRefreshClientComponent.tsx"
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Session from "supertokens-auth-react/recipe/session";
+import SuperTokens from "supertokens-auth-react";
+
+export const TryRefreshComponent = () => {
+ const router = useRouter();
+ const [didError, setDidError] = useState(false);
+
+ useEffect(() => {
+ /**
+ * `attemptRefreshingSession` will call the refresh token endpoint to try and
+ * refresh the session. This will throw an error if the session cannot be refreshed.
+ */
+ void Session.attemptRefreshingSession()
+ .then((hasSession) => {
+ /**
+ * If the user has a valid session, we reload the page to restart the flow
+ * with valid session tokens
+ */
+ if (hasSession) {
+ router.refresh();
+ } else {
+ SuperTokens.redirectToAuth();
+ }
+ })
+ .catch(() => {
+ setDidError(true);
+ });
+ }, []);
+
+ /**
+ * We add this check to make sure we handle the case where the refresh API fails with
+ * an unexpected error
+ */
+ if (didError) {
+ return Something went wrong, please reload the page
;
+ }
+
+ return Loading...
;
+};
+```
+
+### Using `SessionAuthForNextJS` and checking for sessions
+
+We then create a server component that can check if the session exists and return any session information we may need:
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ // `session` will be undefined if it does not exist or has expired
+ if (!session) {
+ if (!hasToken) {
+ /**
+ * This means that the user is not logged in. If you want to display some other UI in this
+ * case, you can do so here.
+ */
+ return redirect("/auth");
+ }
+
+ /**
+ * `hasInvalidClaims` indicates that session claims did not pass validation. For example if email
+ * verification is required but the user's email has not been verified.
+ */
+ if (hasInvalidClaims) {
+ /**
+ * This will make sure that the user is redirected based on their session claims. For example they
+ * will be redirected to the email verification screen if needed.
+ *
+ * We pass in no children in this case to prevent hydration issues and still be able to redirect the
+ * user.
+ */
+ return ;
+ } else {
+ /**
+ * This means that the session does not exist but we have session tokens for the user. In this case
+ * the `TryRefreshComponent` will try to refresh the session.
+ */
+ return ;
+ }
+ }
+
+ /**
+ * SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
+ * It will redirect to the login page if the session does not exist etc.
+ */
+ return (
+
+
+ Your user id is: {session.getUserId()}
+
+
+ );
+}
+```
+
+`getSSRSession` is a utility function we created in the [previous step](./session-helpers.mdx). The `TryRefreshComponent` is a client component that checks if a session exists and tries to refresh the session if it is expired.
+
+And then we can modify the `/app/page.tsx` file to use our server component
+
+```tsx title="app/page.tsx"
+declare let HomePage: any; // typecheck-only, removed from output
+import styles from './page.module.css'
+// @ts-ignore
+import { HomePage } from "./components/home";
+
+export default function Home() {
+ return (
+
+
+
+ )
+}
+```
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+:::important
+An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx).
+:::
diff --git a/v2/passwordless/nextjs/app-directory/server-components-requests.mdx b/v2/passwordless/nextjs/app-directory/server-components-requests.mdx
new file mode 100644
index 000000000..536a7e39e
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/server-components-requests.mdx
@@ -0,0 +1,83 @@
+---
+id: server-components-requests
+title: 7. Making requests from Server Components
+hide_title: true
+---
+
+
+
+
+# 7. Making requests from Server Components
+
+Lets modify the Home page we made in a [previous step](../protecting-route.mdx) to make a call to this API
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ if (!session) {
+ if (!hasToken) {
+ return redirect("/auth");
+ }
+
+ if (hasInvalidClaims) {
+ return ;
+ } else {
+ return ;
+ }
+ }
+
+ // highlight-start
+ const userInfoResponse = await fetch('http://localhost:3000/api/user', {
+ headers: {
+ /**
+ * We read the access token from the session and use that as a Bearer token when
+ * making network requests.
+ */
+ Authorization: 'Bearer ' + session.getAccessToken(),
+ },
+ });
+
+ let message = "";
+
+ if (userInfoResponse.status === 200) {
+ message = `Your user id is: ${session.getUserId()}`
+ } else if (userInfoResponse.status === 500) {
+ message = "Something went wrong"
+ } else if (userInfoResponse.status === 401) {
+ // The TryRefreshComponent will try to refresh the session
+ return
+ } else if (userInfoResponse.status === 403) {
+ // SessionAuthForNextJS will redirect based on which claim is invalid
+ return ;
+ }
+
+ // You can use `userInfoResponse` to read the users session information
+ // highlight-end
+
+ return (
+
+
+ {message}
+
+
+ );
+}
+```
+
+We use `session` returned by `getSSRSession` to get the access token of the user. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the information. You can use the `session` object to fetch other information such as `session.getUserId()`.
diff --git a/v2/passwordless/nextjs/app-directory/session-helpers.mdx b/v2/passwordless/nextjs/app-directory/session-helpers.mdx
new file mode 100644
index 000000000..f168b0b6a
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/session-helpers.mdx
@@ -0,0 +1,166 @@
+---
+id: session-helpers
+title: 4. Add helper functions for sessions
+hide_title: true
+---
+
+
+
+
+# 4. Add helper functions for sessions
+
+To make it easy to access session information and protect our API routes we will create some helper functions:
+
+```ts title="app/sessionUtils.ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { serialize } from "cookie";
+import { cookies, headers } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+import Session, { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";
+import { PreParsedRequest, CollectingResponse } from "supertokens-node/framework/custom";
+import { HTTPMethod } from "supertokens-node/types";
+// @ts-ignore
+import { ensureSuperTokensInit } from "./config/backend";
+
+ensureSuperTokensInit();
+
+export async function getSSRSession(
+ req?: NextRequest,
+ options?: VerifySessionOptions
+): Promise<{
+ session: SessionContainer | undefined;
+ hasToken: boolean;
+ hasInvalidClaims: boolean;
+ baseResponse: CollectingResponse;
+ nextResponse?: NextResponse;
+}> {
+ const query = req !== undefined ? Object.fromEntries(new URL(req.url).searchParams.entries()) : {};
+ const parsedCookies: Record = Object.fromEntries(
+ (req !== undefined ? req.cookies : cookies()).getAll().map((cookie) => [cookie.name, cookie.value])
+ );
+
+ /**
+ * Pre parsed request is a wrapper exposed by SuperTokens. It is used as a helper to detect if the
+ * original request contains session tokens. We then use this pre parsed request to call `getSession`
+ * to check if there is a valid session.
+ */
+ let baseRequest = new PreParsedRequest({
+ method: req !== undefined ? (req.method as HTTPMethod) : "get",
+ url: req !== undefined ? req.url : "",
+ query: query,
+ headers: req !== undefined ? req.headers : headers(),
+ cookies: parsedCookies,
+ getFormBody: () => req!.formData(),
+ getJSONBody: () => req!.json(),
+ });
+
+ /**
+ * Collecting response is a wrapper exposed by SuperTokens. In this case we are using an empty
+ * CollectingResponse when calling `getSession`. If the request contains valid session tokens
+ * the SuperTokens SDK will attach all the relevant tokens to the collecting response object which
+ * we can then use to return those session tokens in the final result (refer to `withSession` in this file)
+ */
+ let baseResponse = new CollectingResponse();
+
+ try {
+ /**
+ * `getSession` will throw if session is required and there is no valid session. You can use
+ * `options` to configure whether or not you want to require sessions when calling `getSSRSession`
+ */
+ let session = await Session.getSession(baseRequest, baseResponse, options);
+ return {
+ session,
+ hasInvalidClaims: false,
+ hasToken: session !== undefined,
+ baseResponse,
+ };
+ } catch (err) {
+ if (Session.Error.isErrorFromSuperTokens(err)) {
+ return {
+ hasToken: err.type !== Session.Error.UNAUTHORISED,
+ /**
+ * This allows us to protect our routes based on the current session claims. For example
+ * this will be true if email verification is required but the user has not verified their
+ * email.
+ */
+ hasInvalidClaims: err.type === Session.Error.INVALID_CLAIMS,
+ session: undefined,
+ baseResponse,
+ nextResponse: new NextResponse("Authentication required", {
+ status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
+ }),
+ };
+ } else {
+ throw err;
+ }
+ }
+}
+
+export async function withSession(
+ request: NextRequest,
+ handler: (session: SessionContainer | undefined) => Promise,
+ options?: VerifySessionOptions
+) {
+ let { session, nextResponse, baseResponse } = await getSSRSession(request, options);
+ if (nextResponse) {
+ return nextResponse;
+ }
+
+ let userResponse = await handler(session);
+
+ let didAddCookies = false;
+ let didAddHeaders = false;
+
+ /**
+ * Base response is the response from SuperTokens that contains all the session tokens.
+ * We add all cookies and headers in the base response to the final response from the
+ * API to make sure sessions work correctly.
+ */
+ for (const respCookie of baseResponse.cookies) {
+ didAddCookies = true;
+ userResponse.headers.append(
+ "Set-Cookie",
+ serialize(respCookie.key, respCookie.value, {
+ domain: respCookie.domain,
+ expires: new Date(respCookie.expires),
+ httpOnly: respCookie.httpOnly,
+ path: respCookie.path,
+ sameSite: respCookie.sameSite,
+ secure: respCookie.secure,
+ })
+ );
+ }
+
+ baseResponse.headers.forEach((value, key) => {
+ didAddHeaders = true;
+ userResponse.headers.set(key, value);
+ });
+
+ /**
+ * For some deployment services (Vercel for example) production builds can return cached results for
+ * APIs with older header values. In this case if the session tokens have changed (because of refreshing
+ * for example) the cached result would still contain the older tokens and sessions would stop working.
+ *
+ * As a result, if we add cookies or headers from base response we also set the Cache-Control header
+ * to make sure that the final result is not a cached version.
+ */
+ if (didAddCookies || didAddHeaders) {
+ if (!userResponse.headers.has("Cache-Control")) {
+ // This is needed for production deployments with Vercel
+ userResponse.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+ }
+
+ return userResponse;
+}
+```
+
+- `getSSRSession` will be used in our frontend routes to get session information when rendering on the server side. This function will:
+ - `{..., session: Object, hasToken: true}` if a session exists
+ - `{..., session: undefined, hasToken: false}` if a session does not exist
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: false}` if the session is expired
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: true}` If the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
+
+- `withSession` will be used as a session guard for each of our API routes. If a session exists it will be passed to the callback, which is where we will write our API logic. If no session exists it will pass `undefined` to the callback. This function will:
+ - Return status `401` if the session has expired
+ - Return status `403` if the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
diff --git a/v2/passwordless/nextjs/app-directory/session-verification-middleware.mdx b/v2/passwordless/nextjs/app-directory/session-verification-middleware.mdx
new file mode 100644
index 000000000..967c12710
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/session-verification-middleware.mdx
@@ -0,0 +1,89 @@
+---
+id: session-verification-middleware
+title: Using the Next.js middleware
+hide_title: true
+---
+
+
+
+
+# Using the Next.js middleware
+
+:::important
+This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step.
+:::
+
+## Setting up the middleware
+
+In the middleware we check if a session exists using the `withSession` helper function we created [here](./session-helpers.mdx) and set the user's user id to the request headers using the session object. You can set other information in the same way.
+
+:::caution
+You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx).
+:::
+
+```tsx title="middleware.tsx"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse } from 'next/server'
+import type { NextRequest } from 'next/server'
+import { SessionContainer } from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { withSession } from './app/sessionUtils';
+
+
+export async function middleware(
+ request: NextRequest & { session?: SessionContainer }
+) {
+ if (request.headers.has("x-user-id")) {
+ console.warn("The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.");
+ request.headers.delete("x-user-id");
+ }
+
+ if (request.nextUrl.pathname.startsWith('/api/auth')) {
+ /**
+ * /api/auth/* endpoints are exposed by the SuperTokens SDK,
+ * we do not want to modify the request for these routes
+ */
+ return NextResponse.next()
+ }
+
+ return withSession(request, async (session) => {
+ if (session === undefined) {
+ return NextResponse.next()
+ }
+ return NextResponse.next({
+ headers: {
+ // You cannot attach the full session object here
+ 'x-user-id': session.getUserId(),
+ },
+ })
+ })
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+## Fetching the user ID in your APIs
+
+The middleware will run for all routes, we can read information set by the middleware in the API routes:
+
+```tsx title="app/api/userid/route.ts"
+import { NextResponse, NextRequest } from "next/server";
+
+export function GET(request: NextRequest) {
+ const userId = request.headers.get("x-user-id");
+
+ // The middleware only adds the userId if a session exists
+ if (userId === null) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ userId,
+ });
+}
+```
+
+This creates a `GET` request for the `/api/userid` route which returns the user id of the currently logged in user.
diff --git a/v2/passwordless/nextjs/app-directory/session-verification-session-guard.mdx b/v2/passwordless/nextjs/app-directory/session-verification-session-guard.mdx
new file mode 100644
index 000000000..5b64f688a
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/session-verification-session-guard.mdx
@@ -0,0 +1,50 @@
+---
+id: session-verification-session-guard
+title: Adding a session guard to each API route
+hide_title: true
+---
+
+
+
+
+# Adding a session guard to each API route
+
+:::note
+This is applicable for when the frontend calls an API in the `/app/api` folder.
+:::
+
+For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
+
+Create a new file `/app/api/user/route.ts`
+
+- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/api/user/route.ts).
+
+```ts title="app/api/user/route.ts"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse, NextRequest } from "next/server";
+import SuperTokens from "supertokens-node";
+// @ts-ignore
+import { withSession } from "../../sessionUtils";
+
+export function GET(request: NextRequest) {
+ return withSession(request, async (session) => {
+ if (!session) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ note: "Fetch any data from your application for authenticated user after using verifySession middleware",
+ userId: session.getUserId(),
+ sessionHandle: session.getHandle(),
+ accessTokenPayload: session.getAccessTokenPayload(),
+ });
+ });
+}
+```
+
+In the above snippet we are creating a `GET` handler for the `/api/user` route. We call the `withSession` helper function we created in a [previous step](./session-helpers.mdx), the function will pass the session object in the callback which we then use to read user information. If a session does not exist `undefined` will be passed intead.
+
+The `withSession` guard will return:
+- Status `401` if the session does not exist or has expired
+- Stauts `403` if the session claims fail their validation. For example if email verification is required but the user's email is not verified.
diff --git a/v2/passwordless/nextjs/app-directory/setting-up-backend.mdx b/v2/passwordless/nextjs/app-directory/setting-up-backend.mdx
new file mode 100644
index 000000000..6beea3b80
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/setting-up-backend.mdx
@@ -0,0 +1,82 @@
+---
+id: setting-up-backend
+title: 3. Adding auth APIs
+hide_title: true
+---
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import AppInfoForm from "/src/components/appInfoForm"
+
+# 3. Adding auth APIs
+
+We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`.
+
+## 1) Create the API folder
+- Be sure to create the `auth` folder in the `app/api/` folder.
+- `[[...path]].tsx` will use the `getAppDirRequestHandler` helper function exposed by `supertokens-node` which helps in calling all the APIs like sign in, sign up etc. (the full folder path should be `/app/api/auth/[[...path]].tsx`).
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/api/auth/%5B...path%5D).
+
+## 2) Expose the SuperTokens APIs
+
+
+
+```tsx title="app/api/auth/[[...path]].ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { getAppDirRequestHandler } from 'supertokens-node/nextjs';
+import { NextRequest, NextResponse } from 'next/server';
+// @ts-ignore
+import { ensureSuperTokensInit } from '../../../config/backend';
+
+ensureSuperTokensInit();
+
+const handleCall = getAppDirRequestHandler(NextResponse);
+
+export async function GET(request: NextRequest) {
+ const res = await handleCall(request);
+ if (!res.headers.has('Cache-Control')) {
+ // This is needed for production deployments with Vercel
+ res.headers.set(
+ 'Cache-Control',
+ 'no-cache, no-store, max-age=0, must-revalidate'
+ )
+ }
+ return res;
+}
+
+export async function POST(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function DELETE(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PUT(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PATCH(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function HEAD(request: NextRequest) {
+ return handleCall(request);
+}
+```
+
+:::note
+In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.
+:::
+
+
+
+## 3) Use the login widget
+If you are now able to sign in or sign up, this means the backend setup is done correctly! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
diff --git a/v2/passwordless/nextjs/app-directory/setting-up-frontend.mdx b/v2/passwordless/nextjs/app-directory/setting-up-frontend.mdx
new file mode 100644
index 000000000..635a11d76
--- /dev/null
+++ b/v2/passwordless/nextjs/app-directory/setting-up-frontend.mdx
@@ -0,0 +1,72 @@
+---
+id: setting-up-frontend
+title: 2. Showing the Login UI
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {
+ PreBuiltOrCustomUISwitcher,
+ PreBuiltUIContent,
+ CustomUIContent,
+} from "/src/components/preBuiltOrCustomUISwitcher";
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import AppInfoForm from "/src/components/appInfoForm";
+
+# 2. Showing the Login UI
+
+
+
+
+
+## 1) Create the `app/auth/[[...path]].tsx` page
+- Be sure to create the `auth` folder in the `app` folder.
+- `[[...path]].tsx` will contain the component for showing SuperTokens UI
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/auth/%5B%5B...path%5D%5D).
+
+## 2) Create the `Auth` component:
+
+```tsx title="app/auth/[[...path]].tsx"
+'use client';
+
+import { useEffect } from 'react';
+import { redirectToAuth } from 'supertokens-auth-react';
+import SuperTokens from 'supertokens-auth-react/ui';
+import { ^{recipePreBuiltUINameCapitalLetters} } from "supertokens-auth-react/recipe/^{codeImportRecipeName}/prebuiltui";
+
+export default function Auth() {
+ // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
+ useEffect(() => {
+ if (
+ SuperTokens.canHandleRoute([^{recipePreBuiltUINameCapitalLetters}]) === false
+ ) {
+ redirectToAuth({ redirectBack: false });
+ }
+ }, []);
+
+ if (typeof window !== 'undefined') {
+ return SuperTokens.getRoutingComponent([^{recipePreBuiltUINameCapitalLetters}]);
+ }
+
+ return null;
+}
+```
+
+## 3) Visit `/auth` page on your website
+
+If you see a login UI, then you have successfully completed this step! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
+
+
+
+
+
+You need to build your own UI. Please follow the docs after the "Initialisation" section in the "Using your own UI" section for how to build out the various auth flows.
+
+
+
+
diff --git a/v2/passwordless/nextjs/init.mdx b/v2/passwordless/nextjs/init.mdx
index 1a4136d9a..6b1aa5fdc 100644
--- a/v2/passwordless/nextjs/init.mdx
+++ b/v2/passwordless/nextjs/init.mdx
@@ -36,7 +36,6 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
- Create an `appInfo.ts` inside the `config` folder.
- Create a `backendConfig.ts` inside the `config` folder.
- Create a `frontendConfig.ts` inside the `config` folder.
-- An example of these files can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/config/).
## 3) Create the `appInfo` configuration.
@@ -227,7 +226,6 @@ export const backendConfig = (): TypeInput => {
## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
- Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app).
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx)
```tsx title="/pages/_app.tsx"
diff --git a/v2/passwordless/nextjs/protecting-route.mdx b/v2/passwordless/nextjs/protecting-route.mdx
index 03e6187c7..21505368e 100644
--- a/v2/passwordless/nextjs/protecting-route.mdx
+++ b/v2/passwordless/nextjs/protecting-route.mdx
@@ -38,10 +38,6 @@ export default function Home() {
}
```
-:::important
-An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L36).
-:::
-
:::tip Test by navigating to `/`
You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
:::
diff --git a/v2/passwordless/nextjs/session-verification/in-api.mdx b/v2/passwordless/nextjs/session-verification/in-api.mdx
index a8220ae96..e0d57c781 100644
--- a/v2/passwordless/nextjs/session-verification/in-api.mdx
+++ b/v2/passwordless/nextjs/session-verification/in-api.mdx
@@ -18,7 +18,6 @@ This is applicable for when the frontend calls an API in the `/pages/api` folder
For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
## 1) Create a new file `/pages/api/user.ts`
-- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/user.ts).
## 2) Call the `supertokens.init` function
Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file.
diff --git a/v2/passwordless/nextjs/session-verification/in-ssr.mdx b/v2/passwordless/nextjs/session-verification/in-ssr.mdx
index e33b15cf2..4e7a8cdb0 100644
--- a/v2/passwordless/nextjs/session-verification/in-ssr.mdx
+++ b/v2/passwordless/nextjs/session-verification/in-ssr.mdx
@@ -24,8 +24,6 @@ For this guide, we will assume that we want to pass the logged in user's ID as a
If using `getInitialProps`, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
:::
-An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L15).
-
```tsx
import Session from 'supertokens-node/recipe/session'
@@ -90,7 +88,6 @@ Do not use the `verifySession` function here. The reason is that this will send
- The following will refresh a session if needed, for all your website pages
- This goes in the `/pages/_app.tsx` file
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx#L16).
```tsx title="/pages/_app.tsx"
diff --git a/v2/passwordless/nextjs/setting-up-backend.mdx b/v2/passwordless/nextjs/setting-up-backend.mdx
index 89c0d6321..3658e19f8 100644
--- a/v2/passwordless/nextjs/setting-up-backend.mdx
+++ b/v2/passwordless/nextjs/setting-up-backend.mdx
@@ -18,7 +18,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by
## 1) Create the `pages/api/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages/api/` folder.
- `[[...path]].tsx` will use the middleware exposed by `supertokens-node` which exposes all the APIs like sign in, sign up etc..
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/auth/%5B%5B...path%5D%5D.ts).
## 2) Expose the SuperTokens APIs
diff --git a/v2/passwordless/nextjs/setting-up-frontend.mdx b/v2/passwordless/nextjs/setting-up-frontend.mdx
index f1ff8f414..9f7cf1295 100644
--- a/v2/passwordless/nextjs/setting-up-frontend.mdx
+++ b/v2/passwordless/nextjs/setting-up-frontend.mdx
@@ -27,7 +27,6 @@ import AppInfoForm from "/src/components/appInfoForm";
## 1) Create the `pages/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages` folder.
- `[[...path]].tsx` will contain the component for showing SuperTokens UI
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/auth/%5B%5B...path%5D%5D.tsx).
## 2) Create the `Auth` component:
diff --git a/v2/passwordless/sidebars.js b/v2/passwordless/sidebars.js
index 62765bf04..18ee657e4 100644
--- a/v2/passwordless/sidebars.js
+++ b/v2/passwordless/sidebars.js
@@ -175,20 +175,48 @@ module.exports = {
logoUrl: '/img/logos/next-logo.png'
},
items: [
- "nextjs/about",
- "nextjs/init",
- "nextjs/setting-up-frontend",
- "nextjs/setting-up-backend",
- "nextjs/protecting-route",
{
type: 'category',
- label: '5. Session verification',
+ label: 'Using the App directory',
items: [
- "nextjs/session-verification/in-api",
- "nextjs/session-verification/in-ssr"
+ "nextjs/app-directory/about",
+ "nextjs/app-directory/init",
+ "nextjs/app-directory/setting-up-frontend",
+ "nextjs/app-directory/setting-up-backend",
+ "nextjs/app-directory/session-helpers",
+ "nextjs/app-directory/protecting-route",
+ {
+ type: "category",
+ label: "6. Checking for sessions in API routes",
+ items: [
+ "nextjs/app-directory/session-verification-session-guard",
+ "nextjs/app-directory/session-verification-middleware",
+ ],
+ },
+ "nextjs/app-directory/server-components-requests",
+ "nextjs/app-directory/next-steps"
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Using the Pages directory',
+ items: [
+ "nextjs/about",
+ "nextjs/init",
+ "nextjs/setting-up-frontend",
+ "nextjs/setting-up-backend",
+ "nextjs/protecting-route",
+ {
+ type: 'category',
+ label: '5. Session verification',
+ items: [
+ "nextjs/session-verification/in-api",
+ "nextjs/session-verification/in-ssr"
+ ],
+ },
+ "nextjs/next-steps"
],
},
- "nextjs/next-steps"
],
},
{
diff --git a/v2/src/plugins/codeTypeChecking/jsEnv/package.json b/v2/src/plugins/codeTypeChecking/jsEnv/package.json
index d6c3971da..eb2b12c4f 100644
--- a/v2/src/plugins/codeTypeChecking/jsEnv/package.json
+++ b/v2/src/plugins/codeTypeChecking/jsEnv/package.json
@@ -46,7 +46,7 @@
"koa-router": "^10.1.1",
"libphonenumber-js": "^1.10.18",
"loopback": "^3.28.0",
- "next": "^12.0.10",
+ "next": "^13.5.6",
"nextjs-cors": "^2.1.0",
"react-router-dom": "^6.2.1",
"react-router-dom5": "npm:react-router-dom@^5.3.0",
@@ -62,4 +62,4 @@
"supertokens-website-script": "github:supertokens/supertokens-website#17.0",
"typescript": "^4.9.5"
}
-}
\ No newline at end of file
+}
diff --git a/v2/thirdparty/nextjs/app-directory/about.mdx b/v2/thirdparty/nextjs/app-directory/about.mdx
new file mode 100644
index 000000000..a82d63e1a
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/about.mdx
@@ -0,0 +1,65 @@
+---
+id: about
+title: About
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Adding a website page to display the auth related widgets (on `/auth` by default)
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend).
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+:::note
+This example app uses our pre built UI
+:::
+
+
+
+
+
diff --git a/v2/thirdparty/nextjs/app-directory/init.mdx b/v2/thirdparty/nextjs/app-directory/init.mdx
new file mode 100644
index 000000000..8bf4aebf6
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/init.mdx
@@ -0,0 +1,428 @@
+---
+id: init
+title: 1. Configuration
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import {Question, Answer}from "/src/components/question"
+import AppInfoForm from "/src/components/appInfoForm"
+import CoreInjector from "/src/components/coreInjector"
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+# 1. Configuration
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ websiteDomain: "^{form_websiteDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+ websiteBasePath: "^{form_websiteBasePath}"
+}
+
+```
+
+
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyReact, {Google, Facebook} from 'supertokens-auth-react/recipe/thirdparty'
+import SessionReact from 'supertokens-auth-react/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import Router from 'next/navigation'
+import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types'
+import { useRouter } from "next/navigation";
+
+const routerInfo: { router?: ReturnType; pathName?: string } =
+ {};
+
+export function setRouter(
+ router: ReturnType,
+ pathName: string,
+) {
+ routerInfo.router = router;
+ routerInfo.pathName = pathName;
+}
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyReact.init({
+ signInAndUpFeature: {
+ providers: [
+ ThirdPartyReact.Google.init(),
+ ThirdPartyReact.Facebook.init(),
+ ThirdPartyReact.Apple.init(),
+ ThirdPartyReact.Github.init(),
+ ],
+ },
+ }),
+ SessionReact.init(),
+ ],
+ windowHandler: (original) => ({
+ ...original,
+ location: {
+ ...original.location,
+ getPathName: () => routerInfo.pathName!,
+ assign: (url) => routerInfo.router!.push(url.toString()),
+ setHref: (url) => routerInfo.router!.push(url.toString()),
+ },
+ }),
+ }
+}
+```
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyWebJs from 'supertokens-web-js/recipe/thirdparty'
+import SessionWebJs from 'supertokens-web-js/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { SuperTokensConfig } from "supertokens-web-js/types"
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyWebJs.init(),
+ SessionWebJs.init(),
+ ],
+ }
+}
+```
+
+
+
+
+
+## 5) Create a backend config function
+
+
+
+
+
+```tsx title="/config/backendConfig.ts"
+import SuperTokens from "supertokens-node";
+import ThirdPartyNode from 'supertokens-node/recipe/thirdparty'
+import SessionNode from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { TypeInput } from "supertokens-node/types";
+
+export const backendConfig = (): TypeInput => {
+ return {
+ framework: "express",
+ supertokens: {
+ ^{coreInjector_connection_uri_comment}
+ connectionURI: ^{coreInjector_uri}
+ ^{coreInjector_api_key_commented}apiKey: ^{coreInjector_api_key},
+ },
+ appInfo,
+ recipeList: [
+ ThirdPartyNode.init({
+ signInAndUpFeature: {
+ // We have provided you with development keys which you can use for testing.
+ // IMPORTANT: Please replace them with your own OAuth keys for production use.
+ providers: [{
+ config: {
+ thirdPartyId: "google",
+ clients: [{
+ clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
+ clientSecret: "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"
+ }]
+ }
+ }, {
+ config: {
+ thirdPartyId: "github",
+ clients: [{
+ clientId: "467101b197249757c71f",
+ clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd"
+ }]
+ }
+ }, {
+ config: {
+ thirdPartyId: "apple",
+ clients: [{
+ clientId: "4398792-io.supertokens.example.service",
+ additionalConfig: {
+ keyId: "7M48Y4RYDL",
+ privateKey:
+ "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
+ teamId: "YWQCXGJRJL",
+ }
+ }]
+ }
+ }],
+ }
+ }),
+ SessionNode.init(),
+ ],
+ isInServerlessEnv: true,
+ }
+}
+
+let initialized = false;
+// This function is used in your APIs to make sure SuperTokens is initialised
+export function ensureSuperTokensInit() {
+ if (!initialized) {
+ SuperTokens.init(backendConfig());
+ initialized = true;
+ }
+}
+```
+
+`ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initiailised before using any functionality exposed by the backend SDKs.
+
+**When you want to generate your own keys**, please refer to the corresponding documentation to get your client ids and client secrets for each of the below providers:
+
+
+Google
+
+- Generate your client ID and secret by following the [docs here](https://support.google.com/cloud/answer/6158849?hl=en)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/google`
+
+
+
+
+Github
+
+- Generate your client ID and secret by following the [docs here](https://docs.github.com/en/developers/apps/creating-an-oauth-app)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/github`
+
+
+
+
+Facebook
+
+- Generate your client ID and secret by following the [docs here](https://developers.facebook.com/docs/development/create-an-app)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/facebook`
+
+:::info Note
+Make sure to enable `https` to be able to use the test users of the Facebook app. On `http://localhost`, the login flow can be verified only with the app's admin user.
+:::
+
+
+
+
+Apple
+
+- Generate your client ID and secret by following [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003)
+- Set the authorisation callback URL to `^{form_apiDomain}^{form_apiBasePathForCallbacks}/callback/apple`. Note that Apple doesn't allow `localhost` in the URL. So if you are in dev mode, you can use the dev keys we have provided above.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
+
+- Create a client component `/app/components/supertokensProvider.tsx`. This file will initialise SuperTokens and wrap its children with the `SuperTokensWrapper` component
+- Modify the `/app/layout.tsx` file to use the `SuperTokensProvider` component. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/layout.tsx)
+
+```tsx title="/app/components/supertokensProvider.tsx"
+'use client';
+declare let frontendConfig: any; // typecheck-only, removed from output
+declare let setRouter: any; // typecheck-only, removed from output
+import React from 'react';
+import { SuperTokensWrapper } from 'supertokens-auth-react';
+import SuperTokensReact from 'supertokens-auth-react';
+// @ts-ignore
+import { frontendConfig, setRouter } from '../config/frontend';
+import { usePathname, useRouter } from 'next/navigation';
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ SuperTokensReact.init(frontendConfig());
+}
+
+export const SuperTokensProvider: React.FC> = ({
+ children,
+}) => {
+ setRouter(useRouter(), usePathname() || window.location.pathname);
+
+ return {children};
+};
+```
+
+```tsx title="/app/layout.tsx"
+declare let SuperTokensProvider: any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { SuperTokensProvider } from "./components/supertokensProvider";
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions
+
+- Modify the `/app/layout.tsx` file to initialise the SuperTokens SDK. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+
+
+```tsx title="/app/layout.tsx"
+declare let frontendConfig: () => any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { frontendConfig } from '../config/frontend';
+import SuperTokensWebJs from 'supertokens-web-js'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ // highlight-next-line
+ SuperTokensWebJs.init(frontendConfig())
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2/thirdparty/nextjs/app-directory/next-steps.mdx b/v2/thirdparty/nextjs/app-directory/next-steps.mdx
new file mode 100644
index 000000000..b26f14fad
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/next-steps.mdx
@@ -0,0 +1,35 @@
+---
+id: next-steps
+title: 8. Next steps
+hide_title: true
+---
+
+
+
+
+import {Question, Answer}from "/src/components/question"
+
+# 6. Next steps
+
+## Setting up the core and database
+ {
+ return (
+ Are you using https://try.supertokens.com
as the connection URI in the init function?
+ )
+ }}>
+
+
+You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options:
+- [Managed service](../quick-setup/core/saas-setup)
+- Self hosted with your own database ([With Docker](../quick-setup/core/with-docker) or [Without Docker](../quick-setup/core/without-docker))
+
+
+
+
+:::success
+You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.
+:::
+
+
+
diff --git a/v2/thirdparty/nextjs/app-directory/protecting-route.mdx b/v2/thirdparty/nextjs/app-directory/protecting-route.mdx
new file mode 100644
index 000000000..19c693a80
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/protecting-route.mdx
@@ -0,0 +1,255 @@
+---
+id: protecting-route
+title: 5. Checking for sessions in frontend routes
+hide_title: true
+---
+
+
+
+
+# 5. Checking for sessions in frontend routes
+
+Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page.
+
+## Sessions with Client Components
+
+Lets create a client component for the `/` route of our website.
+
+### Using the `SessionAuth` wrapper component
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ return (
+
+
+ Hello world
+
+
+ );
+}
+```
+
+`SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page.
+
+:::caution
+At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.
+
+Refer to the next section of this page to learn how to use sessions on the server side.
+:::
+
+### Using `useSessionContext`
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { useSessionContext } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ const session = useSessionContext();
+
+ if (session.loading) {
+ return Loading...
;
+ }
+
+ if (session.doesSessionExist === false) {
+ return Session does not exist
;
+ }
+
+ return (
+
+
+
+ Client side component got userId: {session.userId}
+
+
+
+ );
+}
+```
+
+`useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly.
+
+:::info
+`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.
+:::
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+## Sessions with Server Components
+
+### Creating some helper Components
+
+#### Creating a wrapper around `SessionAuth`
+Let's say we want to protect the home page of your website (`/` route). First we will create a wrapper around the `SessionAuth` component provided by SuperTokens to allow us to use it on both server side and client side.
+
+```tsx title="app/components/sessionAuthForNextJS.tsx"
+"use client";
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+
+type Props = Parameters[0] & {
+ children?: React.ReactNode | undefined;
+};
+
+export const SessionAuthForNextJS = (props: Props) => {
+ if (typeof window === "undefined") {
+ return props.children;
+ }
+
+ return {props.children};
+};
+```
+
+This is a client component that renders just its children on the server side and renders the children wrapped with `SessionAuth` on the client side.
+
+#### Creating the `TryRefreshComponent`
+
+This component will refresh the user's session if their current session has expired.
+
+```tsx title="app/components/tryRefreshClientComponent.tsx"
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Session from "supertokens-auth-react/recipe/session";
+import SuperTokens from "supertokens-auth-react";
+
+export const TryRefreshComponent = () => {
+ const router = useRouter();
+ const [didError, setDidError] = useState(false);
+
+ useEffect(() => {
+ /**
+ * `attemptRefreshingSession` will call the refresh token endpoint to try and
+ * refresh the session. This will throw an error if the session cannot be refreshed.
+ */
+ void Session.attemptRefreshingSession()
+ .then((hasSession) => {
+ /**
+ * If the user has a valid session, we reload the page to restart the flow
+ * with valid session tokens
+ */
+ if (hasSession) {
+ router.refresh();
+ } else {
+ SuperTokens.redirectToAuth();
+ }
+ })
+ .catch(() => {
+ setDidError(true);
+ });
+ }, []);
+
+ /**
+ * We add this check to make sure we handle the case where the refresh API fails with
+ * an unexpected error
+ */
+ if (didError) {
+ return Something went wrong, please reload the page
;
+ }
+
+ return Loading...
;
+};
+```
+
+### Using `SessionAuthForNextJS` and checking for sessions
+
+We then create a server component that can check if the session exists and return any session information we may need:
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ // `session` will be undefined if it does not exist or has expired
+ if (!session) {
+ if (!hasToken) {
+ /**
+ * This means that the user is not logged in. If you want to display some other UI in this
+ * case, you can do so here.
+ */
+ return redirect("/auth");
+ }
+
+ /**
+ * `hasInvalidClaims` indicates that session claims did not pass validation. For example if email
+ * verification is required but the user's email has not been verified.
+ */
+ if (hasInvalidClaims) {
+ /**
+ * This will make sure that the user is redirected based on their session claims. For example they
+ * will be redirected to the email verification screen if needed.
+ *
+ * We pass in no children in this case to prevent hydration issues and still be able to redirect the
+ * user.
+ */
+ return ;
+ } else {
+ /**
+ * This means that the session does not exist but we have session tokens for the user. In this case
+ * the `TryRefreshComponent` will try to refresh the session.
+ */
+ return ;
+ }
+ }
+
+ /**
+ * SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
+ * It will redirect to the login page if the session does not exist etc.
+ */
+ return (
+
+
+ Your user id is: {session.getUserId()}
+
+
+ );
+}
+```
+
+`getSSRSession` is a utility function we created in the [previous step](./session-helpers.mdx). The `TryRefreshComponent` is a client component that checks if a session exists and tries to refresh the session if it is expired.
+
+And then we can modify the `/app/page.tsx` file to use our server component
+
+```tsx title="app/page.tsx"
+declare let HomePage: any; // typecheck-only, removed from output
+import styles from './page.module.css'
+// @ts-ignore
+import { HomePage } from "./components/home";
+
+export default function Home() {
+ return (
+
+
+
+ )
+}
+```
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+:::important
+An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx).
+:::
diff --git a/v2/thirdparty/nextjs/app-directory/server-components-requests.mdx b/v2/thirdparty/nextjs/app-directory/server-components-requests.mdx
new file mode 100644
index 000000000..536a7e39e
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/server-components-requests.mdx
@@ -0,0 +1,83 @@
+---
+id: server-components-requests
+title: 7. Making requests from Server Components
+hide_title: true
+---
+
+
+
+
+# 7. Making requests from Server Components
+
+Lets modify the Home page we made in a [previous step](../protecting-route.mdx) to make a call to this API
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ if (!session) {
+ if (!hasToken) {
+ return redirect("/auth");
+ }
+
+ if (hasInvalidClaims) {
+ return ;
+ } else {
+ return ;
+ }
+ }
+
+ // highlight-start
+ const userInfoResponse = await fetch('http://localhost:3000/api/user', {
+ headers: {
+ /**
+ * We read the access token from the session and use that as a Bearer token when
+ * making network requests.
+ */
+ Authorization: 'Bearer ' + session.getAccessToken(),
+ },
+ });
+
+ let message = "";
+
+ if (userInfoResponse.status === 200) {
+ message = `Your user id is: ${session.getUserId()}`
+ } else if (userInfoResponse.status === 500) {
+ message = "Something went wrong"
+ } else if (userInfoResponse.status === 401) {
+ // The TryRefreshComponent will try to refresh the session
+ return
+ } else if (userInfoResponse.status === 403) {
+ // SessionAuthForNextJS will redirect based on which claim is invalid
+ return ;
+ }
+
+ // You can use `userInfoResponse` to read the users session information
+ // highlight-end
+
+ return (
+
+
+ {message}
+
+
+ );
+}
+```
+
+We use `session` returned by `getSSRSession` to get the access token of the user. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the information. You can use the `session` object to fetch other information such as `session.getUserId()`.
diff --git a/v2/thirdparty/nextjs/app-directory/session-helpers.mdx b/v2/thirdparty/nextjs/app-directory/session-helpers.mdx
new file mode 100644
index 000000000..f168b0b6a
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/session-helpers.mdx
@@ -0,0 +1,166 @@
+---
+id: session-helpers
+title: 4. Add helper functions for sessions
+hide_title: true
+---
+
+
+
+
+# 4. Add helper functions for sessions
+
+To make it easy to access session information and protect our API routes we will create some helper functions:
+
+```ts title="app/sessionUtils.ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { serialize } from "cookie";
+import { cookies, headers } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+import Session, { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";
+import { PreParsedRequest, CollectingResponse } from "supertokens-node/framework/custom";
+import { HTTPMethod } from "supertokens-node/types";
+// @ts-ignore
+import { ensureSuperTokensInit } from "./config/backend";
+
+ensureSuperTokensInit();
+
+export async function getSSRSession(
+ req?: NextRequest,
+ options?: VerifySessionOptions
+): Promise<{
+ session: SessionContainer | undefined;
+ hasToken: boolean;
+ hasInvalidClaims: boolean;
+ baseResponse: CollectingResponse;
+ nextResponse?: NextResponse;
+}> {
+ const query = req !== undefined ? Object.fromEntries(new URL(req.url).searchParams.entries()) : {};
+ const parsedCookies: Record = Object.fromEntries(
+ (req !== undefined ? req.cookies : cookies()).getAll().map((cookie) => [cookie.name, cookie.value])
+ );
+
+ /**
+ * Pre parsed request is a wrapper exposed by SuperTokens. It is used as a helper to detect if the
+ * original request contains session tokens. We then use this pre parsed request to call `getSession`
+ * to check if there is a valid session.
+ */
+ let baseRequest = new PreParsedRequest({
+ method: req !== undefined ? (req.method as HTTPMethod) : "get",
+ url: req !== undefined ? req.url : "",
+ query: query,
+ headers: req !== undefined ? req.headers : headers(),
+ cookies: parsedCookies,
+ getFormBody: () => req!.formData(),
+ getJSONBody: () => req!.json(),
+ });
+
+ /**
+ * Collecting response is a wrapper exposed by SuperTokens. In this case we are using an empty
+ * CollectingResponse when calling `getSession`. If the request contains valid session tokens
+ * the SuperTokens SDK will attach all the relevant tokens to the collecting response object which
+ * we can then use to return those session tokens in the final result (refer to `withSession` in this file)
+ */
+ let baseResponse = new CollectingResponse();
+
+ try {
+ /**
+ * `getSession` will throw if session is required and there is no valid session. You can use
+ * `options` to configure whether or not you want to require sessions when calling `getSSRSession`
+ */
+ let session = await Session.getSession(baseRequest, baseResponse, options);
+ return {
+ session,
+ hasInvalidClaims: false,
+ hasToken: session !== undefined,
+ baseResponse,
+ };
+ } catch (err) {
+ if (Session.Error.isErrorFromSuperTokens(err)) {
+ return {
+ hasToken: err.type !== Session.Error.UNAUTHORISED,
+ /**
+ * This allows us to protect our routes based on the current session claims. For example
+ * this will be true if email verification is required but the user has not verified their
+ * email.
+ */
+ hasInvalidClaims: err.type === Session.Error.INVALID_CLAIMS,
+ session: undefined,
+ baseResponse,
+ nextResponse: new NextResponse("Authentication required", {
+ status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
+ }),
+ };
+ } else {
+ throw err;
+ }
+ }
+}
+
+export async function withSession(
+ request: NextRequest,
+ handler: (session: SessionContainer | undefined) => Promise,
+ options?: VerifySessionOptions
+) {
+ let { session, nextResponse, baseResponse } = await getSSRSession(request, options);
+ if (nextResponse) {
+ return nextResponse;
+ }
+
+ let userResponse = await handler(session);
+
+ let didAddCookies = false;
+ let didAddHeaders = false;
+
+ /**
+ * Base response is the response from SuperTokens that contains all the session tokens.
+ * We add all cookies and headers in the base response to the final response from the
+ * API to make sure sessions work correctly.
+ */
+ for (const respCookie of baseResponse.cookies) {
+ didAddCookies = true;
+ userResponse.headers.append(
+ "Set-Cookie",
+ serialize(respCookie.key, respCookie.value, {
+ domain: respCookie.domain,
+ expires: new Date(respCookie.expires),
+ httpOnly: respCookie.httpOnly,
+ path: respCookie.path,
+ sameSite: respCookie.sameSite,
+ secure: respCookie.secure,
+ })
+ );
+ }
+
+ baseResponse.headers.forEach((value, key) => {
+ didAddHeaders = true;
+ userResponse.headers.set(key, value);
+ });
+
+ /**
+ * For some deployment services (Vercel for example) production builds can return cached results for
+ * APIs with older header values. In this case if the session tokens have changed (because of refreshing
+ * for example) the cached result would still contain the older tokens and sessions would stop working.
+ *
+ * As a result, if we add cookies or headers from base response we also set the Cache-Control header
+ * to make sure that the final result is not a cached version.
+ */
+ if (didAddCookies || didAddHeaders) {
+ if (!userResponse.headers.has("Cache-Control")) {
+ // This is needed for production deployments with Vercel
+ userResponse.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+ }
+
+ return userResponse;
+}
+```
+
+- `getSSRSession` will be used in our frontend routes to get session information when rendering on the server side. This function will:
+ - `{..., session: Object, hasToken: true}` if a session exists
+ - `{..., session: undefined, hasToken: false}` if a session does not exist
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: false}` if the session is expired
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: true}` If the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
+
+- `withSession` will be used as a session guard for each of our API routes. If a session exists it will be passed to the callback, which is where we will write our API logic. If no session exists it will pass `undefined` to the callback. This function will:
+ - Return status `401` if the session has expired
+ - Return status `403` if the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
diff --git a/v2/thirdparty/nextjs/app-directory/session-verification-middleware.mdx b/v2/thirdparty/nextjs/app-directory/session-verification-middleware.mdx
new file mode 100644
index 000000000..967c12710
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/session-verification-middleware.mdx
@@ -0,0 +1,89 @@
+---
+id: session-verification-middleware
+title: Using the Next.js middleware
+hide_title: true
+---
+
+
+
+
+# Using the Next.js middleware
+
+:::important
+This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step.
+:::
+
+## Setting up the middleware
+
+In the middleware we check if a session exists using the `withSession` helper function we created [here](./session-helpers.mdx) and set the user's user id to the request headers using the session object. You can set other information in the same way.
+
+:::caution
+You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx).
+:::
+
+```tsx title="middleware.tsx"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse } from 'next/server'
+import type { NextRequest } from 'next/server'
+import { SessionContainer } from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { withSession } from './app/sessionUtils';
+
+
+export async function middleware(
+ request: NextRequest & { session?: SessionContainer }
+) {
+ if (request.headers.has("x-user-id")) {
+ console.warn("The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.");
+ request.headers.delete("x-user-id");
+ }
+
+ if (request.nextUrl.pathname.startsWith('/api/auth')) {
+ /**
+ * /api/auth/* endpoints are exposed by the SuperTokens SDK,
+ * we do not want to modify the request for these routes
+ */
+ return NextResponse.next()
+ }
+
+ return withSession(request, async (session) => {
+ if (session === undefined) {
+ return NextResponse.next()
+ }
+ return NextResponse.next({
+ headers: {
+ // You cannot attach the full session object here
+ 'x-user-id': session.getUserId(),
+ },
+ })
+ })
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+## Fetching the user ID in your APIs
+
+The middleware will run for all routes, we can read information set by the middleware in the API routes:
+
+```tsx title="app/api/userid/route.ts"
+import { NextResponse, NextRequest } from "next/server";
+
+export function GET(request: NextRequest) {
+ const userId = request.headers.get("x-user-id");
+
+ // The middleware only adds the userId if a session exists
+ if (userId === null) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ userId,
+ });
+}
+```
+
+This creates a `GET` request for the `/api/userid` route which returns the user id of the currently logged in user.
diff --git a/v2/thirdparty/nextjs/app-directory/session-verification-session-guard.mdx b/v2/thirdparty/nextjs/app-directory/session-verification-session-guard.mdx
new file mode 100644
index 000000000..5b64f688a
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/session-verification-session-guard.mdx
@@ -0,0 +1,50 @@
+---
+id: session-verification-session-guard
+title: Adding a session guard to each API route
+hide_title: true
+---
+
+
+
+
+# Adding a session guard to each API route
+
+:::note
+This is applicable for when the frontend calls an API in the `/app/api` folder.
+:::
+
+For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
+
+Create a new file `/app/api/user/route.ts`
+
+- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/api/user/route.ts).
+
+```ts title="app/api/user/route.ts"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse, NextRequest } from "next/server";
+import SuperTokens from "supertokens-node";
+// @ts-ignore
+import { withSession } from "../../sessionUtils";
+
+export function GET(request: NextRequest) {
+ return withSession(request, async (session) => {
+ if (!session) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ note: "Fetch any data from your application for authenticated user after using verifySession middleware",
+ userId: session.getUserId(),
+ sessionHandle: session.getHandle(),
+ accessTokenPayload: session.getAccessTokenPayload(),
+ });
+ });
+}
+```
+
+In the above snippet we are creating a `GET` handler for the `/api/user` route. We call the `withSession` helper function we created in a [previous step](./session-helpers.mdx), the function will pass the session object in the callback which we then use to read user information. If a session does not exist `undefined` will be passed intead.
+
+The `withSession` guard will return:
+- Status `401` if the session does not exist or has expired
+- Stauts `403` if the session claims fail their validation. For example if email verification is required but the user's email is not verified.
diff --git a/v2/thirdparty/nextjs/app-directory/setting-up-backend.mdx b/v2/thirdparty/nextjs/app-directory/setting-up-backend.mdx
new file mode 100644
index 000000000..6beea3b80
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/setting-up-backend.mdx
@@ -0,0 +1,82 @@
+---
+id: setting-up-backend
+title: 3. Adding auth APIs
+hide_title: true
+---
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import AppInfoForm from "/src/components/appInfoForm"
+
+# 3. Adding auth APIs
+
+We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`.
+
+## 1) Create the API folder
+- Be sure to create the `auth` folder in the `app/api/` folder.
+- `[[...path]].tsx` will use the `getAppDirRequestHandler` helper function exposed by `supertokens-node` which helps in calling all the APIs like sign in, sign up etc. (the full folder path should be `/app/api/auth/[[...path]].tsx`).
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/api/auth/%5B...path%5D).
+
+## 2) Expose the SuperTokens APIs
+
+
+
+```tsx title="app/api/auth/[[...path]].ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { getAppDirRequestHandler } from 'supertokens-node/nextjs';
+import { NextRequest, NextResponse } from 'next/server';
+// @ts-ignore
+import { ensureSuperTokensInit } from '../../../config/backend';
+
+ensureSuperTokensInit();
+
+const handleCall = getAppDirRequestHandler(NextResponse);
+
+export async function GET(request: NextRequest) {
+ const res = await handleCall(request);
+ if (!res.headers.has('Cache-Control')) {
+ // This is needed for production deployments with Vercel
+ res.headers.set(
+ 'Cache-Control',
+ 'no-cache, no-store, max-age=0, must-revalidate'
+ )
+ }
+ return res;
+}
+
+export async function POST(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function DELETE(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PUT(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PATCH(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function HEAD(request: NextRequest) {
+ return handleCall(request);
+}
+```
+
+:::note
+In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.
+:::
+
+
+
+## 3) Use the login widget
+If you are now able to sign in or sign up, this means the backend setup is done correctly! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
diff --git a/v2/thirdparty/nextjs/app-directory/setting-up-frontend.mdx b/v2/thirdparty/nextjs/app-directory/setting-up-frontend.mdx
new file mode 100644
index 000000000..635a11d76
--- /dev/null
+++ b/v2/thirdparty/nextjs/app-directory/setting-up-frontend.mdx
@@ -0,0 +1,72 @@
+---
+id: setting-up-frontend
+title: 2. Showing the Login UI
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {
+ PreBuiltOrCustomUISwitcher,
+ PreBuiltUIContent,
+ CustomUIContent,
+} from "/src/components/preBuiltOrCustomUISwitcher";
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import AppInfoForm from "/src/components/appInfoForm";
+
+# 2. Showing the Login UI
+
+
+
+
+
+## 1) Create the `app/auth/[[...path]].tsx` page
+- Be sure to create the `auth` folder in the `app` folder.
+- `[[...path]].tsx` will contain the component for showing SuperTokens UI
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/auth/%5B%5B...path%5D%5D).
+
+## 2) Create the `Auth` component:
+
+```tsx title="app/auth/[[...path]].tsx"
+'use client';
+
+import { useEffect } from 'react';
+import { redirectToAuth } from 'supertokens-auth-react';
+import SuperTokens from 'supertokens-auth-react/ui';
+import { ^{recipePreBuiltUINameCapitalLetters} } from "supertokens-auth-react/recipe/^{codeImportRecipeName}/prebuiltui";
+
+export default function Auth() {
+ // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
+ useEffect(() => {
+ if (
+ SuperTokens.canHandleRoute([^{recipePreBuiltUINameCapitalLetters}]) === false
+ ) {
+ redirectToAuth({ redirectBack: false });
+ }
+ }, []);
+
+ if (typeof window !== 'undefined') {
+ return SuperTokens.getRoutingComponent([^{recipePreBuiltUINameCapitalLetters}]);
+ }
+
+ return null;
+}
+```
+
+## 3) Visit `/auth` page on your website
+
+If you see a login UI, then you have successfully completed this step! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
+
+
+
+
+
+You need to build your own UI. Please follow the docs after the "Initialisation" section in the "Using your own UI" section for how to build out the various auth flows.
+
+
+
+
diff --git a/v2/thirdparty/nextjs/init.mdx b/v2/thirdparty/nextjs/init.mdx
index 86b3bfb68..f2cee4d00 100644
--- a/v2/thirdparty/nextjs/init.mdx
+++ b/v2/thirdparty/nextjs/init.mdx
@@ -31,7 +31,6 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
- Create an `appInfo.ts` inside the `config` folder.
- Create a `backendConfig.ts` inside the `config` folder.
- Create a `frontendConfig.ts` inside the `config` folder.
-- An example of these files can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/config/).
## 3) Create the `appInfo` configuration.
@@ -301,7 +300,6 @@ Make sure to enable `https` to be able to use the test users of the Facebook app
## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
- Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app).
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx)
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdparty/nextjs/protecting-route.mdx b/v2/thirdparty/nextjs/protecting-route.mdx
index 03e6187c7..21505368e 100644
--- a/v2/thirdparty/nextjs/protecting-route.mdx
+++ b/v2/thirdparty/nextjs/protecting-route.mdx
@@ -38,10 +38,6 @@ export default function Home() {
}
```
-:::important
-An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L36).
-:::
-
:::tip Test by navigating to `/`
You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
:::
diff --git a/v2/thirdparty/nextjs/session-verification/in-api.mdx b/v2/thirdparty/nextjs/session-verification/in-api.mdx
index a8220ae96..e0d57c781 100644
--- a/v2/thirdparty/nextjs/session-verification/in-api.mdx
+++ b/v2/thirdparty/nextjs/session-verification/in-api.mdx
@@ -18,7 +18,6 @@ This is applicable for when the frontend calls an API in the `/pages/api` folder
For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
## 1) Create a new file `/pages/api/user.ts`
-- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/user.ts).
## 2) Call the `supertokens.init` function
Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file.
diff --git a/v2/thirdparty/nextjs/session-verification/in-ssr.mdx b/v2/thirdparty/nextjs/session-verification/in-ssr.mdx
index e33b15cf2..4e7a8cdb0 100644
--- a/v2/thirdparty/nextjs/session-verification/in-ssr.mdx
+++ b/v2/thirdparty/nextjs/session-verification/in-ssr.mdx
@@ -24,8 +24,6 @@ For this guide, we will assume that we want to pass the logged in user's ID as a
If using `getInitialProps`, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
:::
-An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L15).
-
```tsx
import Session from 'supertokens-node/recipe/session'
@@ -90,7 +88,6 @@ Do not use the `verifySession` function here. The reason is that this will send
- The following will refresh a session if needed, for all your website pages
- This goes in the `/pages/_app.tsx` file
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx#L16).
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdparty/nextjs/setting-up-backend.mdx b/v2/thirdparty/nextjs/setting-up-backend.mdx
index 89c0d6321..3658e19f8 100644
--- a/v2/thirdparty/nextjs/setting-up-backend.mdx
+++ b/v2/thirdparty/nextjs/setting-up-backend.mdx
@@ -18,7 +18,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by
## 1) Create the `pages/api/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages/api/` folder.
- `[[...path]].tsx` will use the middleware exposed by `supertokens-node` which exposes all the APIs like sign in, sign up etc..
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/auth/%5B%5B...path%5D%5D.ts).
## 2) Expose the SuperTokens APIs
diff --git a/v2/thirdparty/nextjs/setting-up-frontend.mdx b/v2/thirdparty/nextjs/setting-up-frontend.mdx
index f1ff8f414..9f7cf1295 100644
--- a/v2/thirdparty/nextjs/setting-up-frontend.mdx
+++ b/v2/thirdparty/nextjs/setting-up-frontend.mdx
@@ -27,7 +27,6 @@ import AppInfoForm from "/src/components/appInfoForm";
## 1) Create the `pages/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages` folder.
- `[[...path]].tsx` will contain the component for showing SuperTokens UI
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/auth/%5B%5B...path%5D%5D.tsx).
## 2) Create the `Auth` component:
diff --git a/v2/thirdparty/sidebars.js b/v2/thirdparty/sidebars.js
index 327297b1f..b1a9e862a 100644
--- a/v2/thirdparty/sidebars.js
+++ b/v2/thirdparty/sidebars.js
@@ -174,20 +174,48 @@ module.exports = {
logoUrl: '/img/logos/next-logo.png'
},
items: [
- "nextjs/about",
- "nextjs/init",
- "nextjs/setting-up-frontend",
- "nextjs/setting-up-backend",
- "nextjs/protecting-route",
{
type: 'category',
- label: '5. Session verification',
+ label: 'Using the App directory',
items: [
- "nextjs/session-verification/in-api",
- "nextjs/session-verification/in-ssr"
+ "nextjs/app-directory/about",
+ "nextjs/app-directory/init",
+ "nextjs/app-directory/setting-up-frontend",
+ "nextjs/app-directory/setting-up-backend",
+ "nextjs/app-directory/session-helpers",
+ "nextjs/app-directory/protecting-route",
+ {
+ type: "category",
+ label: "6. Checking for sessions in API routes",
+ items: [
+ "nextjs/app-directory/session-verification-session-guard",
+ "nextjs/app-directory/session-verification-middleware",
+ ],
+ },
+ "nextjs/app-directory/server-components-requests",
+ "nextjs/app-directory/next-steps"
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Using the Pages directory',
+ items: [
+ "nextjs/about",
+ "nextjs/init",
+ "nextjs/setting-up-frontend",
+ "nextjs/setting-up-backend",
+ "nextjs/protecting-route",
+ {
+ type: 'category',
+ label: '5. Session verification',
+ items: [
+ "nextjs/session-verification/in-api",
+ "nextjs/session-verification/in-ssr"
+ ],
+ },
+ "nextjs/next-steps"
],
},
- "nextjs/next-steps"
],
},
{
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/about.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/about.mdx
new file mode 100644
index 000000000..a82d63e1a
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/about.mdx
@@ -0,0 +1,65 @@
+---
+id: about
+title: About
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Adding a website page to display the auth related widgets (on `/auth` by default)
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend).
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+:::note
+This example app uses our pre built UI
+:::
+
+
+
+
+
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/init.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/init.mdx
new file mode 100644
index 000000000..ec26195f6
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/init.mdx
@@ -0,0 +1,426 @@
+---
+id: init
+title: 1. Configuration
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import {Question, Answer}from "/src/components/question"
+import AppInfoForm from "/src/components/appInfoForm"
+import CoreInjector from "/src/components/coreInjector"
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+# 1. Configuration
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ websiteDomain: "^{form_websiteDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+ websiteBasePath: "^{form_websiteBasePath}"
+}
+
+```
+
+
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyEmailPasswordReact from 'supertokens-auth-react/recipe/thirdpartyemailpassword'
+import SessionReact from 'supertokens-auth-react/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import Router from 'next/navigation'
+import { useRouter } from "next/navigation";
+import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types'
+
+const routerInfo: { router?: ReturnType; pathName?: string } =
+ {};
+
+export function setRouter(
+ router: ReturnType,
+ pathName: string,
+) {
+ routerInfo.router = router;
+ routerInfo.pathName = pathName;
+}
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyEmailPasswordReact.init({
+ signInAndUpFeature: {
+ providers: [
+ ThirdPartyEmailPasswordReact.Google.init(),
+ ThirdPartyEmailPasswordReact.Facebook.init(),
+ ThirdPartyEmailPasswordReact.Github.init(),
+ ThirdPartyEmailPasswordReact.Apple.init(),
+ ],
+ },
+ }),
+ SessionReact.init(),
+ ],
+ windowHandler: (original) => ({
+ ...original,
+ location: {
+ ...original.location,
+ getPathName: () => routerInfo.pathName!,
+ assign: (url) => routerInfo.router!.push(url.toString()),
+ setHref: (url) => routerInfo.router!.push(url.toString()),
+ },
+ }),
+ }
+}
+```
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyEmailPasswordWebJs from 'supertokens-web-js/recipe/thirdpartyemailpassword'
+import SessionWebJs from 'supertokens-web-js/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { SuperTokensConfig } from "supertokens-web-js/types"
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyEmailPasswordWebJs.init(),
+ SessionWebJs.init(),
+ ],
+ }
+}
+```
+
+
+
+
+
+## 5) Create a backend config function
+
+
+
+
+
+```tsx title="/config/backendConfig.ts"
+import SuperTokens from "supertokens-node";
+import ThirdPartyEmailPasswordNode from 'supertokens-node/recipe/thirdpartyemailpassword'
+import SessionNode from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { TypeInput } from "supertokens-node/types";
+
+export const backendConfig = (): TypeInput => {
+ return {
+ framework: "express",
+ supertokens: {
+ ^{coreInjector_connection_uri_comment}
+ connectionURI: ^{coreInjector_uri}
+ ^{coreInjector_api_key_commented}apiKey: ^{coreInjector_api_key},
+ },
+ appInfo,
+ recipeList: [
+ ThirdPartyEmailPasswordNode.init({
+ // We have provided you with development keys which you can use for testing.
+ // IMPORTANT: Please replace them with your own OAuth keys for production use.
+ providers: [{
+ config: {
+ thirdPartyId: "google",
+ clients: [{
+ clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
+ clientSecret: "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"
+ }]
+ }
+ }, {
+ config: {
+ thirdPartyId: "github",
+ clients: [{
+ clientId: "467101b197249757c71f",
+ clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd"
+ }]
+ }
+ }, {
+ config: {
+ thirdPartyId: "apple",
+ clients: [{
+ clientId: "4398792-io.supertokens.example.service",
+ additionalConfig: {
+ keyId: "7M48Y4RYDL",
+ privateKey:
+ "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
+ teamId: "YWQCXGJRJL",
+ }
+ }]
+ }
+ }],
+ }),
+ SessionNode.init(),
+ ],
+ isInServerlessEnv: true,
+ }
+}
+
+let initialized = false;
+// This function is used in your APIs to make sure SuperTokens is initialised
+export function ensureSuperTokensInit() {
+ if (!initialized) {
+ SuperTokens.init(backendConfig());
+ initialized = true;
+ }
+}
+```
+
+`ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initiailised before using any functionality exposed by the backend SDKs.
+
+**When you want to generate your own keys**, please refer to the corresponding documentation to get your client ids and client secrets for each of the below providers:
+
+
+Google
+
+- Generate your client ID and secret by following the [docs here](https://support.google.com/cloud/answer/6158849?hl=en)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/google`
+
+
+
+
+Github
+
+- Generate your client ID and secret by following the [docs here](https://docs.github.com/en/developers/apps/creating-an-oauth-app)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/github`
+
+
+
+
+Facebook
+
+- Generate your client ID and secret by following the [docs here](https://developers.facebook.com/docs/development/create-an-app)
+- Set the authorisation callback URL to `^{form_websiteDomain}^{form_websiteBasePathForCallbacks}/callback/facebook`
+
+:::info Note
+Make sure to enable `https` to be able to use the test users of the Facebook app. On `http://localhost`, the login flow can be verified only with the app's admin user.
+:::
+
+
+
+
+Apple
+
+- Generate your client ID and secret by following [this article](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003)
+- Set the authorisation callback URL to `^{form_apiDomain}^{form_apiBasePathForCallbacks}/callback/apple`. Note that Apple doesn't allow `localhost` in the URL. So if you are in dev mode, you can use the dev keys we have provided above.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
+
+- Create a client component `/app/components/supertokensProvider.tsx`. This file will initialise SuperTokens and wrap its children with the `SuperTokensWrapper` component
+- Modify the `/app/layout.tsx` file to use the `SuperTokensProvider` component. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/layout.tsx)
+
+```tsx title="/app/components/supertokensProvider.tsx"
+'use client';
+declare let frontendConfig: any; // typecheck-only, removed from output
+declare let setRouter: any; // typecheck-only, removed from output
+import React from 'react';
+import { SuperTokensWrapper } from 'supertokens-auth-react';
+import SuperTokensReact from 'supertokens-auth-react';
+// @ts-ignore
+import { frontendConfig, setRouter } from '../config/frontend';
+import { usePathname, useRouter } from 'next/navigation';
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ SuperTokensReact.init(frontendConfig());
+}
+
+export const SuperTokensProvider: React.FC> = ({
+ children,
+}) => {
+ setRouter(useRouter(), usePathname() || window.location.pathname);
+
+ return {children};
+};
+```
+
+```tsx title="/app/layout.tsx"
+declare let SuperTokensProvider: any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { SuperTokensProvider } from "./components/supertokensProvider";
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions
+
+- Modify the `/app/layout.tsx` file to initialise the SuperTokens SDK. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+
+
+```tsx title="/app/layout.tsx"
+declare let frontendConfig: () => any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { frontendConfig } from '../config/frontend';
+import SuperTokensWebJs from 'supertokens-web-js'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ // highlight-next-line
+ SuperTokensWebJs.init(frontendConfig())
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/next-steps.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/next-steps.mdx
new file mode 100644
index 000000000..b26f14fad
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/next-steps.mdx
@@ -0,0 +1,35 @@
+---
+id: next-steps
+title: 8. Next steps
+hide_title: true
+---
+
+
+
+
+import {Question, Answer}from "/src/components/question"
+
+# 6. Next steps
+
+## Setting up the core and database
+ {
+ return (
+ Are you using https://try.supertokens.com
as the connection URI in the init function?
+ )
+ }}>
+
+
+You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options:
+- [Managed service](../quick-setup/core/saas-setup)
+- Self hosted with your own database ([With Docker](../quick-setup/core/with-docker) or [Without Docker](../quick-setup/core/without-docker))
+
+
+
+
+:::success
+You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.
+:::
+
+
+
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/protecting-route.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/protecting-route.mdx
new file mode 100644
index 000000000..db88e2d54
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/protecting-route.mdx
@@ -0,0 +1,255 @@
+---
+id: protecting-route
+title: 5. Checking for sessions in frontend routes
+hide_title: true
+---
+
+
+
+
+# 5. Checking for sessions in frontend routes
+
+Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page.
+
+## Sessions with Client Components
+
+Lets create a client component for the `/` route of our website.
+
+### Using the `SessionAuth` wrapper component
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ return (
+
+
+ Hello world
+
+
+ );
+}
+```
+
+`SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page.
+
+:::caution
+At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.
+
+Refer to the next section of this page to learn how to use sessions on the server side.
+:::
+
+### Using `useSessionContext`
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { useSessionContext } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ const session = useSessionContext();
+
+ if (session.loading) {
+ return Loading...
;
+ }
+
+ if (session.doesSessionExist === false) {
+ return Session does not exist
;
+ }
+
+ return (
+
+
+
+ Client side component got userId: {session.userId}
+
+
+
+ );
+}
+```
+
+`useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly.
+
+:::info
+`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.
+:::
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+## Sessions with Server Components
+
+### Creating some helper Components
+
+#### Creating a wrapper around `SessionAuth`
+Let's say we want to protect the home page of your website (`/` route). First we will create a wrapper around the `SessionAuth` component provided by SuperTokens to allow us to use it on both server side and client side.
+
+```tsx title="app/components/sessionAuthForNextJS.tsx"
+"use client";
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+
+type Props = Parameters[0] & {
+ children?: React.ReactNode | undefined;
+};
+
+export const SessionAuthForNextJS = (props: Props) => {
+ if (typeof window === "undefined") {
+ return props.children;
+ }
+
+ return {props.children};
+};
+```
+
+This is a client component that renders just its children on the server side and renders the children wrapped with `SessionAuth` on the client side.
+
+#### Creating the `TryRefreshComponent`
+
+This component will refresh the user's session if their current session has expired.
+
+```tsx title="app/components/tryRefreshClientComponent.tsx"
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Session from "supertokens-auth-react/recipe/session";
+import SuperTokens from "supertokens-auth-react";
+
+export const TryRefreshComponent = () => {
+ const router = useRouter();
+ const [didError, setDidError] = useState(false);
+
+ useEffect(() => {
+ /**
+ * `attemptRefreshingSession` will call the refresh token endpoint to try and
+ * refresh the session. This will throw an error if the session cannot be refreshed.
+ */
+ void Session.attemptRefreshingSession()
+ .then((hasSession) => {
+ /**
+ * If the user has a valid session, we reload the page to restart the flow
+ * with valid session tokens
+ */
+ if (hasSession) {
+ router.refresh();
+ } else {
+ SuperTokens.redirectToAuth();
+ }
+ })
+ .catch(() => {
+ setDidError(true);
+ });
+ }, []);
+
+ /**
+ * We add this check to make sure we handle the case where the refresh API fails with
+ * an unexpected error
+ */
+ if (didError) {
+ return Something went wrong, please reload the page
;
+ }
+
+ return Loading...
;
+};
+```
+
+### Using `SessionAuthForNextJS` and checking for sessions
+
+We then create a server component that can check if the session exists and return any session information we may need:
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ // `session` will be undefined if it does not exist or has expired
+ if (!session) {
+ if (!hasToken) {
+ /**
+ * This means that the user is not logged in. If you want to display some other UI in this
+ * case, you can do so here.
+ */
+ return redirect("/auth");
+ }
+
+ /**
+ * `hasInvalidClaims` indicates that session claims did not pass validation. For example if email
+ * verification is required but the user's email has not been verified.
+ */
+ if (hasInvalidClaims) {
+ /**
+ * This will make sure that the user is redirected based on their session claims. For example they
+ * will be redirected to the email verification screen if needed.
+ *
+ * We pass in no children in this case to prevent hydration issues and still be able to redirect the
+ * user.
+ */
+ return ;
+ } else {
+ /**
+ * This means that the session does not exist but we have session tokens for the user. In this case
+ * the `TryRefreshComponent` will try to refresh the session.
+ */
+ return ;
+ }
+ }
+
+ /**
+ * SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
+ * It will redirect to the login page if the session does not exist etc.
+ */
+ return (
+
+
+ Your user id is: {session.getUserId()}
+
+
+ );
+}
+```
+
+`getSSRSession` is a utility function we created in the [previous step](./session-helpers.mdx). The `TryRefreshComponent` is a client component that checks if a session exists and tries to refresh the session if it is expired.
+
+And then we can modify the `/app/page.tsx` file to use our server component
+
+```tsx title="app/page.tsx"
+declare let HomePage: any; // typecheck-only, removed from output
+import styles from './page.module.css'
+// @ts-ignore
+import { HomePage } from "./components/home";
+
+export default function Home() {
+ return (
+
+
+
+ )
+}
+```
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+:::important
+An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx).
+:::
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/server-components-requests.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/server-components-requests.mdx
new file mode 100644
index 000000000..102a3a2b9
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/server-components-requests.mdx
@@ -0,0 +1,83 @@
+---
+id: server-components-requests
+title: 7. Making requests from Server Components
+hide_title: true
+---
+
+
+
+
+# 7. Making requests from Server Components
+
+Lets modify the Home page we made in a [previous step](../protecting-route.mdx) to make a call to this API
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ if (!session) {
+ if (!hasToken) {
+ return redirect("/auth");
+ }
+
+ if (hasInvalidClaims) {
+ return ;
+ } else {
+ return ;
+ }
+ }
+
+ // highlight-start
+ const userInfoResponse = await fetch('http://localhost:3000/api/user', {
+ headers: {
+ /**
+ * We read the access token from the session and use that as a Bearer token when
+ * making network requests.
+ */
+ Authorization: 'Bearer ' + session.getAccessToken(),
+ },
+ });
+
+ let message = "";
+
+ if (userInfoResponse.status === 200) {
+ message = `Your user id is: ${session.getUserId()}`
+ } else if (userInfoResponse.status === 500) {
+ message = "Something went wrong"
+ } else if (userInfoResponse.status === 401) {
+ // The TryRefreshComponent will try to refresh the session
+ return
+ } else if (userInfoResponse.status === 403) {
+ // SessionAuthForNextJS will redirect based on which claim is invalid
+ return ;
+ }
+
+ // You can use `userInfoResponse` to read the users session information
+ // highlight-end
+
+ return (
+
+
+ {message}
+
+
+ );
+}
+```
+
+We use `session` returned by `getSSRSession` to get the access token of the user. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the information. You can use the `session` object to fetch other information such as `session.getUserId()`.
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/session-helpers.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/session-helpers.mdx
new file mode 100644
index 000000000..154ca4e19
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/session-helpers.mdx
@@ -0,0 +1,166 @@
+---
+id: session-helpers
+title: 4. Add helper functions for sessions
+hide_title: true
+---
+
+
+
+
+# 4. Add helper functions for sessions
+
+To make it easy to access session information and protect our API routes we will create some helper functions:
+
+```ts title="app/sessionUtils.ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { serialize } from "cookie";
+import { cookies, headers } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+import Session, { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";
+import { PreParsedRequest, CollectingResponse } from "supertokens-node/framework/custom";
+import { HTTPMethod } from "supertokens-node/types";
+// @ts-ignore
+import { ensureSuperTokensInit } from "./config/backend";
+
+ensureSuperTokensInit();
+
+export async function getSSRSession(
+ req?: NextRequest,
+ options?: VerifySessionOptions
+): Promise<{
+ session: SessionContainer | undefined;
+ hasToken: boolean;
+ hasInvalidClaims: boolean;
+ baseResponse: CollectingResponse;
+ nextResponse?: NextResponse;
+}> {
+ const query = req !== undefined ? Object.fromEntries(new URL(req.url).searchParams.entries()) : {};
+ const parsedCookies: Record = Object.fromEntries(
+ (req !== undefined ? req.cookies : cookies()).getAll().map((cookie) => [cookie.name, cookie.value])
+ );
+
+ /**
+ * Pre parsed request is a wrapper exposed by SuperTokens. It is used as a helper to detect if the
+ * original request contains session tokens. We then use this pre parsed request to call `getSession`
+ * to check if there is a valid session.
+ */
+ let baseRequest = new PreParsedRequest({
+ method: req !== undefined ? (req.method as HTTPMethod) : "get",
+ url: req !== undefined ? req.url : "",
+ query: query,
+ headers: req !== undefined ? req.headers : headers(),
+ cookies: parsedCookies,
+ getFormBody: () => req!.formData(),
+ getJSONBody: () => req!.json(),
+ });
+
+ /**
+ * Collecting response is a wrapper exposed by SuperTokens. In this case we are using an empty
+ * CollectingResponse when calling `getSession`. If the request contains valid session tokens
+ * the SuperTokens SDK will attach all the relevant tokens to the collecting response object which
+ * we can then use to return those session tokens in the final result (refer to `withSession` in this file)
+ */
+ let baseResponse = new CollectingResponse();
+
+ try {
+ /**
+ * `getSession` will throw if session is required and there is no valid session. You can use
+ * `options` to configure whether or not you want to require sessions when calling `getSSRSession`
+ */
+ let session = await Session.getSession(baseRequest, baseResponse, options);
+ return {
+ session,
+ hasInvalidClaims: false,
+ hasToken: session !== undefined,
+ baseResponse,
+ };
+ } catch (err) {
+ if (Session.Error.isErrorFromSuperTokens(err)) {
+ return {
+ hasToken: err.type !== Session.Error.UNAUTHORISED,
+ /**
+ * This allows us to protect our routes based on the current session claims. For example
+ * this will be true if email verification is required but the user has not verified their
+ * email.
+ */
+ hasInvalidClaims: err.type === Session.Error.INVALID_CLAIMS,
+ session: undefined,
+ baseResponse,
+ nextResponse: new NextResponse("Authentication required", {
+ status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
+ }),
+ };
+ } else {
+ throw err;
+ }
+ }
+}
+
+export async function withSession(
+ request: NextRequest,
+ handler: (session: SessionContainer | undefined) => Promise,
+ options?: VerifySessionOptions
+) {
+ let { session, nextResponse, baseResponse } = await getSSRSession(request, options);
+ if (nextResponse) {
+ return nextResponse;
+ }
+
+ let userResponse = await handler(session);
+
+ let didAddCookies = false;
+ let didAddHeaders = false;
+
+ /**
+ * Base response is the response from SuperTokens that contains all the session tokens.
+ * We add all cookies and headers in the base response to the final response from the
+ * API to make sure sessions work correctly.
+ */
+ for (const respCookie of baseResponse.cookies) {
+ didAddCookies = true;
+ userResponse.headers.append(
+ "Set-Cookie",
+ serialize(respCookie.key, respCookie.value, {
+ domain: respCookie.domain,
+ expires: new Date(respCookie.expires),
+ httpOnly: respCookie.httpOnly,
+ path: respCookie.path,
+ sameSite: respCookie.sameSite,
+ secure: respCookie.secure,
+ })
+ );
+ }
+
+ baseResponse.headers.forEach((value, key) => {
+ didAddHeaders = true;
+ userResponse.headers.set(key, value);
+ });
+
+ /**
+ * For some deployment services (Vercel for example) production builds can return cached results for
+ * APIs with older header values. In this case if the session tokens have changed (because of refreshing
+ * for example) the cached result would still contain the older tokens and sessions would stop working.
+ *
+ * As a result, if we add cookies or headers from base response we also set the Cache-Control header
+ * to make sure that the final result is not a cached version.
+ */
+ if (didAddCookies || didAddHeaders) {
+ if (!userResponse.headers.has("Cache-Control")) {
+ // This is needed for production deployments with Vercel
+ userResponse.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+ }
+
+ return userResponse;
+}
+```
+
+- `getSSRSession` will be used in our frontend routes to get session information when rendering on the server side. This function will:
+ - `{..., session: Object, hasToken: true}` if a session exists
+ - `{..., session: undefined, hasToken: false}` if a session does not exist
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: false}` if the session is expired
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: true}` If the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
+
+- `withSession` will be used as a session guard for each of our API routes. If a session exists it will be passed to the callback, which is where we will write our API logic. If no session exists it will pass `undefined` to the callback. This function will:
+ - Return status `401` if the session has expired
+ - Return status `403` if the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-middleware.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-middleware.mdx
new file mode 100644
index 000000000..866317321
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-middleware.mdx
@@ -0,0 +1,89 @@
+---
+id: session-verification-middleware
+title: Using the Next.js middleware
+hide_title: true
+---
+
+
+
+
+# Using the Next.js middleware
+
+:::important
+This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step.
+:::
+
+## Setting up the middleware
+
+In the middleware we check if a session exists using the `withSession` helper function we created [here](./session-helpers.mdx) and set the user's user id to the request headers using the session object. You can set other information in the same way.
+
+:::caution
+You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx).
+:::
+
+```tsx title="middleware.tsx"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse } from 'next/server'
+import type { NextRequest } from 'next/server'
+import { SessionContainer } from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { withSession } from './app/sessionUtils';
+
+
+export async function middleware(
+ request: NextRequest & { session?: SessionContainer }
+) {
+ if (request.headers.has("x-user-id")) {
+ console.warn("The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.");
+ request.headers.delete("x-user-id");
+ }
+
+ if (request.nextUrl.pathname.startsWith('/api/auth')) {
+ /**
+ * /api/auth/* endpoints are exposed by the SuperTokens SDK,
+ * we do not want to modify the request for these routes
+ */
+ return NextResponse.next()
+ }
+
+ return withSession(request, async (session) => {
+ if (session === undefined) {
+ return NextResponse.next()
+ }
+ return NextResponse.next({
+ headers: {
+ // You cannot attach the full session object here
+ 'x-user-id': session.getUserId(),
+ },
+ })
+ })
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+## Fetching the user ID in your APIs
+
+The middleware will run for all routes, we can read information set by the middleware in the API routes:
+
+```tsx title="app/api/userid/route.ts"
+import { NextResponse, NextRequest } from "next/server";
+
+export function GET(request: NextRequest) {
+ const userId = request.headers.get("x-user-id");
+
+ // The middleware only adds the userId if a session exists
+ if (userId === null) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ userId,
+ });
+}
+```
+
+This creates a `GET` request for the `/api/userid` route which returns the user id of the currently logged in user.
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-session-guard.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-session-guard.mdx
new file mode 100644
index 000000000..11f00d736
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/session-verification-session-guard.mdx
@@ -0,0 +1,50 @@
+---
+id: session-verification-session-guard
+title: Adding a session guard to each API route
+hide_title: true
+---
+
+
+
+
+# Adding a session guard to each API route
+
+:::note
+This is applicable for when the frontend calls an API in the `/app/api` folder.
+:::
+
+For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
+
+Create a new file `/app/api/user/route.ts`
+
+- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/api/user/route.ts).
+
+```ts title="app/api/user/route.ts"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse, NextRequest } from "next/server";
+import SuperTokens from "supertokens-node";
+// @ts-ignore
+import { withSession } from "../../sessionUtils";
+
+export function GET(request: NextRequest) {
+ return withSession(request, async (session) => {
+ if (!session) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ note: "Fetch any data from your application for authenticated user after using verifySession middleware",
+ userId: session.getUserId(),
+ sessionHandle: session.getHandle(),
+ accessTokenPayload: session.getAccessTokenPayload(),
+ });
+ });
+}
+```
+
+In the above snippet we are creating a `GET` handler for the `/api/user` route. We call the `withSession` helper function we created in a [previous step](./session-helpers.mdx), the function will pass the session object in the callback which we then use to read user information. If a session does not exist `undefined` will be passed intead.
+
+The `withSession` guard will return:
+- Status `401` if the session does not exist or has expired
+- Stauts `403` if the session claims fail their validation. For example if email verification is required but the user's email is not verified.
\ No newline at end of file
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-backend.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-backend.mdx
new file mode 100644
index 000000000..6beea3b80
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-backend.mdx
@@ -0,0 +1,82 @@
+---
+id: setting-up-backend
+title: 3. Adding auth APIs
+hide_title: true
+---
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import AppInfoForm from "/src/components/appInfoForm"
+
+# 3. Adding auth APIs
+
+We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`.
+
+## 1) Create the API folder
+- Be sure to create the `auth` folder in the `app/api/` folder.
+- `[[...path]].tsx` will use the `getAppDirRequestHandler` helper function exposed by `supertokens-node` which helps in calling all the APIs like sign in, sign up etc. (the full folder path should be `/app/api/auth/[[...path]].tsx`).
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/api/auth/%5B...path%5D).
+
+## 2) Expose the SuperTokens APIs
+
+
+
+```tsx title="app/api/auth/[[...path]].ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { getAppDirRequestHandler } from 'supertokens-node/nextjs';
+import { NextRequest, NextResponse } from 'next/server';
+// @ts-ignore
+import { ensureSuperTokensInit } from '../../../config/backend';
+
+ensureSuperTokensInit();
+
+const handleCall = getAppDirRequestHandler(NextResponse);
+
+export async function GET(request: NextRequest) {
+ const res = await handleCall(request);
+ if (!res.headers.has('Cache-Control')) {
+ // This is needed for production deployments with Vercel
+ res.headers.set(
+ 'Cache-Control',
+ 'no-cache, no-store, max-age=0, must-revalidate'
+ )
+ }
+ return res;
+}
+
+export async function POST(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function DELETE(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PUT(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PATCH(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function HEAD(request: NextRequest) {
+ return handleCall(request);
+}
+```
+
+:::note
+In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.
+:::
+
+
+
+## 3) Use the login widget
+If you are now able to sign in or sign up, this means the backend setup is done correctly! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
diff --git a/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-frontend.mdx b/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-frontend.mdx
new file mode 100644
index 000000000..635a11d76
--- /dev/null
+++ b/v2/thirdpartyemailpassword/nextjs/app-directory/setting-up-frontend.mdx
@@ -0,0 +1,72 @@
+---
+id: setting-up-frontend
+title: 2. Showing the Login UI
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {
+ PreBuiltOrCustomUISwitcher,
+ PreBuiltUIContent,
+ CustomUIContent,
+} from "/src/components/preBuiltOrCustomUISwitcher";
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import AppInfoForm from "/src/components/appInfoForm";
+
+# 2. Showing the Login UI
+
+
+
+
+
+## 1) Create the `app/auth/[[...path]].tsx` page
+- Be sure to create the `auth` folder in the `app` folder.
+- `[[...path]].tsx` will contain the component for showing SuperTokens UI
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/auth/%5B%5B...path%5D%5D).
+
+## 2) Create the `Auth` component:
+
+```tsx title="app/auth/[[...path]].tsx"
+'use client';
+
+import { useEffect } from 'react';
+import { redirectToAuth } from 'supertokens-auth-react';
+import SuperTokens from 'supertokens-auth-react/ui';
+import { ^{recipePreBuiltUINameCapitalLetters} } from "supertokens-auth-react/recipe/^{codeImportRecipeName}/prebuiltui";
+
+export default function Auth() {
+ // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
+ useEffect(() => {
+ if (
+ SuperTokens.canHandleRoute([^{recipePreBuiltUINameCapitalLetters}]) === false
+ ) {
+ redirectToAuth({ redirectBack: false });
+ }
+ }, []);
+
+ if (typeof window !== 'undefined') {
+ return SuperTokens.getRoutingComponent([^{recipePreBuiltUINameCapitalLetters}]);
+ }
+
+ return null;
+}
+```
+
+## 3) Visit `/auth` page on your website
+
+If you see a login UI, then you have successfully completed this step! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
+
+
+
+
+
+You need to build your own UI. Please follow the docs after the "Initialisation" section in the "Using your own UI" section for how to build out the various auth flows.
+
+
+
+
diff --git a/v2/thirdpartyemailpassword/nextjs/init.mdx b/v2/thirdpartyemailpassword/nextjs/init.mdx
index 45c4f1e9a..d115fd5be 100644
--- a/v2/thirdpartyemailpassword/nextjs/init.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/init.mdx
@@ -32,7 +32,6 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
- Create an `appInfo.ts` inside the `config` folder.
- Create a `backendConfig.ts` inside the `config` folder.
- Create a `frontendConfig.ts` inside the `config` folder.
-- An example of these files can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/config/).
## 3) Create the `appInfo` configuration.
@@ -294,7 +293,6 @@ Make sure to enable `https` to be able to use the test users of the Facebook app
## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
- Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app).
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx)
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdpartyemailpassword/nextjs/protecting-route.mdx b/v2/thirdpartyemailpassword/nextjs/protecting-route.mdx
index b955acd6d..adb5b3dcb 100644
--- a/v2/thirdpartyemailpassword/nextjs/protecting-route.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/protecting-route.mdx
@@ -38,10 +38,6 @@ export default function Home() {
}
```
-:::important
-An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L36).
-:::
-
:::tip Test by navigating to `/`
You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
:::
diff --git a/v2/thirdpartyemailpassword/nextjs/session-verification/in-api.mdx b/v2/thirdpartyemailpassword/nextjs/session-verification/in-api.mdx
index a8220ae96..e0d57c781 100644
--- a/v2/thirdpartyemailpassword/nextjs/session-verification/in-api.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/session-verification/in-api.mdx
@@ -18,7 +18,6 @@ This is applicable for when the frontend calls an API in the `/pages/api` folder
For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
## 1) Create a new file `/pages/api/user.ts`
-- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/user.ts).
## 2) Call the `supertokens.init` function
Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file.
diff --git a/v2/thirdpartyemailpassword/nextjs/session-verification/in-ssr.mdx b/v2/thirdpartyemailpassword/nextjs/session-verification/in-ssr.mdx
index e33b15cf2..4e7a8cdb0 100644
--- a/v2/thirdpartyemailpassword/nextjs/session-verification/in-ssr.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/session-verification/in-ssr.mdx
@@ -24,8 +24,6 @@ For this guide, we will assume that we want to pass the logged in user's ID as a
If using `getInitialProps`, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
:::
-An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L15).
-
```tsx
import Session from 'supertokens-node/recipe/session'
@@ -90,7 +88,6 @@ Do not use the `verifySession` function here. The reason is that this will send
- The following will refresh a session if needed, for all your website pages
- This goes in the `/pages/_app.tsx` file
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx#L16).
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdpartyemailpassword/nextjs/setting-up-backend.mdx b/v2/thirdpartyemailpassword/nextjs/setting-up-backend.mdx
index 89c0d6321..3658e19f8 100644
--- a/v2/thirdpartyemailpassword/nextjs/setting-up-backend.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/setting-up-backend.mdx
@@ -18,7 +18,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by
## 1) Create the `pages/api/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages/api/` folder.
- `[[...path]].tsx` will use the middleware exposed by `supertokens-node` which exposes all the APIs like sign in, sign up etc..
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/auth/%5B%5B...path%5D%5D.ts).
## 2) Expose the SuperTokens APIs
diff --git a/v2/thirdpartyemailpassword/nextjs/setting-up-frontend.mdx b/v2/thirdpartyemailpassword/nextjs/setting-up-frontend.mdx
index bd7ef00c3..6c0ab1129 100644
--- a/v2/thirdpartyemailpassword/nextjs/setting-up-frontend.mdx
+++ b/v2/thirdpartyemailpassword/nextjs/setting-up-frontend.mdx
@@ -27,7 +27,6 @@ import AppInfoForm from "/src/components/appInfoForm";
## 1) Create the `pages/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages` folder.
- `[[...path]].tsx` will contain the component for showing SuperTokens UI
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/auth/%5B%5B...path%5D%5D.tsx).
## 2) Create the `Auth` component:
diff --git a/v2/thirdpartyemailpassword/sidebars.js b/v2/thirdpartyemailpassword/sidebars.js
index 40f724017..d8ca24e41 100644
--- a/v2/thirdpartyemailpassword/sidebars.js
+++ b/v2/thirdpartyemailpassword/sidebars.js
@@ -179,20 +179,48 @@ module.exports = {
logoUrl: '/img/logos/next-logo.png'
},
items: [
- "nextjs/about",
- "nextjs/init",
- "nextjs/setting-up-frontend",
- "nextjs/setting-up-backend",
- "nextjs/protecting-route",
{
type: 'category',
- label: '5. Session verification',
+ label: 'Using the App directory',
items: [
- "nextjs/session-verification/in-api",
- "nextjs/session-verification/in-ssr"
+ "nextjs/app-directory/about",
+ "nextjs/app-directory/init",
+ "nextjs/app-directory/setting-up-frontend",
+ "nextjs/app-directory/setting-up-backend",
+ "nextjs/app-directory/session-helpers",
+ "nextjs/app-directory/protecting-route",
+ {
+ type: "category",
+ label: "6. Checking for sessions in API routes",
+ items: [
+ "nextjs/app-directory/session-verification-session-guard",
+ "nextjs/app-directory/session-verification-middleware",
+ ],
+ },
+ "nextjs/app-directory/server-components-requests",
+ "nextjs/app-directory/next-steps"
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Using the Pages directory',
+ items: [
+ "nextjs/about",
+ "nextjs/init",
+ "nextjs/setting-up-frontend",
+ "nextjs/setting-up-backend",
+ "nextjs/protecting-route",
+ {
+ type: 'category',
+ label: '5. Session verification',
+ items: [
+ "nextjs/session-verification/in-api",
+ "nextjs/session-verification/in-ssr"
+ ],
+ },
+ "nextjs/next-steps"
],
},
- "nextjs/next-steps"
],
},
{
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/about.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/about.mdx
new file mode 100644
index 000000000..a82d63e1a
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/about.mdx
@@ -0,0 +1,65 @@
+---
+id: about
+title: About
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Adding a website page to display the auth related widgets (on `/auth` by default)
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+
+
+
+
+# Overview steps
+
+Integrating SuperTokens with a Next.js app involves:
+- Calling the frontend and backend init functions
+- Building the various auth flows as per the [custom UI setup guide](../custom-ui/init/frontend).
+- Creating a serverless function to expose the auth related APIs which will be consumed by the frontend widgets (on `/api/auth/` by default)
+- Protecting website routes: Displaying them only when a user is logged in, else redirecting them to the login page
+- Performing session verification:
+ - In your APIs
+ - In your frontend routes
+
+## Try an example app
+
+Download and run an example NextJS app quickly using the following command:
+
+```bash
+npx create-supertokens-app@latest --frontend=next --recipe=^{codeImportRecipeName}
+```
+
+:::note
+This example app uses our pre built UI
+:::
+
+
+
+
+
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/init.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/init.mdx
new file mode 100644
index 000000000..660106f76
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/init.mdx
@@ -0,0 +1,357 @@
+---
+id: init
+title: 1. Configuration
+hide_title: true
+show_ui_switcher: true
+---
+
+import { PasswordlessFrontendForm } from "/src/components/snippetConfigForm/passwordlessFrontendForm";
+import { PasswordlessBackendForm } from "/src/components/snippetConfigForm/passwordlessBackendForm";
+import BackendDeliveryMethod from "../../../passwordless/reusableMD/backendDeliveryMethod.mdx"
+
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import {Question, Answer}from "/src/components/question"
+import AppInfoForm from "/src/components/appInfoForm"
+import CoreInjector from "/src/components/coreInjector"
+import {PreBuiltOrCustomUISwitcher, PreBuiltUIContent, CustomUIContent} from "/src/components/preBuiltOrCustomUISwitcher"
+
+# 1. Configuration
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ websiteDomain: "^{form_websiteDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+ websiteBasePath: "^{form_websiteBasePath}"
+}
+
+```
+
+
+
+
+
+
+
+## 1) Install supertokens package
+```bash
+yarn add supertokens-node supertokens-web-js nextjs-cors
+```
+
+## 2) Create configuration files
+- Create a `config` folder in the root directory of your project
+- Create an `appInfo.ts` inside the `config` folder.
+- Create a `backendConfig.ts` inside the `config` folder.
+- Create a `frontendConfig.ts` inside the `config` folder.
+
+
+## 3) Create the `appInfo` configuration.
+
+
+
+```tsx title="/config/appInfo.ts"
+
+export const appInfo = {
+ // learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
+ appName: "^{form_appName}",
+ apiDomain: "^{form_apiDomain}",
+ apiBasePath: "^{form_apiBasePath}",
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyPasswordlessReact from 'supertokens-auth-react/recipe/thirdpartypasswordless'
+import SessionReact from 'supertokens-auth-react/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import Router from 'next/navigation'
+import { SuperTokensConfig } from 'supertokens-auth-react/lib/build/types'
+import { useRouter } from "next/navigation";
+
+const routerInfo: { router?: ReturnType; pathName?: string } =
+ {};
+
+export function setRouter(
+ router: ReturnType,
+ pathName: string,
+) {
+ routerInfo.router = router;
+ routerInfo.pathName = pathName;
+}
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyPasswordlessReact.init({
+ contactMethod: "^{form_contactMethod}"
+ }),
+ SessionReact.init(),
+ ],
+ windowHandler: (original) => ({
+ ...original,
+ location: {
+ ...original.location,
+ getPathName: () => routerInfo.pathName!,
+ assign: (url) => routerInfo.router!.push(url.toString()),
+ setHref: (url) => routerInfo.router!.push(url.toString()),
+ },
+ }),
+ }
+}
+```
+
+
+
+
+
+## 4) Create a frontend config function
+
+```tsx title="/config/frontendConfig.ts"
+import ThirdPartyPasswordlessWebJs from 'supertokens-web-js/recipe/thirdpartypasswordless'
+import SessionWebJs from 'supertokens-web-js/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { SuperTokensConfig } from "supertokens-web-js/types"
+
+export const frontendConfig = (): SuperTokensConfig => {
+ return {
+ appInfo,
+ recipeList: [
+ ThirdPartyPasswordlessWebJs.init(),
+ SessionWebJs.init(),
+ ],
+ }
+}
+```
+
+
+
+
+
+## 5) Create a backend config function
+
+
+
+
+
+
+```tsx title="/config/backendConfig.ts"
+import SuperTokens from "supertokens-node";
+import ThirdPartyPasswordlessNode from 'supertokens-node/recipe/thirdpartypasswordless'
+import SessionNode from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { appInfo } from './appInfo'
+import { TypeInput } from "supertokens-node/types";
+
+export const backendConfig = (): TypeInput => {
+ return {
+ framework: "express",
+ supertokens: {
+ ^{coreInjector_connection_uri_comment}
+ connectionURI: ^{coreInjector_uri}
+ ^{coreInjector_api_key_commented}apiKey: ^{coreInjector_api_key},
+ },
+ appInfo,
+ recipeList: [
+ ThirdPartyPasswordlessNode.init({
+ flowType: "^{form_flowType}",
+ contactMethod: "^{form_contactMethod}"
+ }),
+ SessionNode.init(),
+ ],
+ isInServerlessEnv: true,
+ }
+}
+
+let initialized = false;
+// This function is used in your APIs to make sure SuperTokens is initialised
+export function ensureSuperTokensInit() {
+ if (!initialized) {
+ SuperTokens.init(backendConfig());
+ initialized = true;
+ }
+}
+```
+
+`ensureSuperTokensinit` is a helper function that can be used in your API routes to make sure SuperTokens is initiailised before using any functionality exposed by the backend SDKs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
+
+- Create a client component `/app/components/supertokensProvider.tsx`. This file will initialise SuperTokens and wrap its children with the `SuperTokensWrapper` component
+- Modify the `/app/layout.tsx` file to use the `SuperTokensProvider` component. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/layout.tsx)
+
+```tsx title="/app/components/supertokensProvider.tsx"
+'use client';
+declare let frontendConfig: any; // typecheck-only, removed from output
+declare let setRouter: any; // typecheck-only, removed from output
+import React from 'react';
+import { SuperTokensWrapper } from 'supertokens-auth-react';
+import SuperTokensReact from 'supertokens-auth-react';
+// @ts-ignore
+import { frontendConfig, setRouter } from '../config/frontend';
+import { usePathname, useRouter } from 'next/navigation';
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ SuperTokensReact.init(frontendConfig());
+}
+
+export const SuperTokensProvider: React.FC> = ({
+ children,
+}) => {
+ setRouter(useRouter(), usePathname() || window.location.pathname);
+
+ return {children};
+};
+```
+
+```tsx title="/app/layout.tsx"
+declare let SuperTokensProvider: any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { SuperTokensProvider } from "./components/supertokensProvider";
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+ {children}
+
+
+ )
+}
+```
+
+
+
+
+
+## ^{nextjsinitlastnumber}) Call the frontend `init` functions
+
+- Modify the `/app/layout.tsx` file to initialise the SuperTokens SDK. You can learn more about this file [here](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required).
+
+
+```tsx title="/app/layout.tsx"
+declare let frontendConfig: () => any; // typecheck-only, removed from output
+import './globals.css'
+import type { Metadata } from 'next'
+import { Inter } from 'next/font/google'
+// @ts-ignore
+import { frontendConfig } from '../config/frontend';
+import SuperTokensWebJs from 'supertokens-web-js'
+
+const inter = Inter({ subsets: ['latin'] })
+
+export const metadata: Metadata = {
+ title: 'Create Next App',
+ description: 'Generated by create next app',
+}
+
+if (typeof window !== 'undefined') {
+ // we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
+ // highlight-next-line
+ SuperTokensWebJs.init(frontendConfig())
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+```
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/next-steps.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/next-steps.mdx
new file mode 100644
index 000000000..b26f14fad
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/next-steps.mdx
@@ -0,0 +1,35 @@
+---
+id: next-steps
+title: 8. Next steps
+hide_title: true
+---
+
+
+
+
+import {Question, Answer}from "/src/components/question"
+
+# 6. Next steps
+
+## Setting up the core and database
+ {
+ return (
+ Are you using https://try.supertokens.com
as the connection URI in the init function?
+ )
+ }}>
+
+
+You need to now setup an instance of the SuperTokens core for your app (that your backend should connect to). You have two options:
+- [Managed service](../quick-setup/core/saas-setup)
+- Self hosted with your own database ([With Docker](../quick-setup/core/with-docker) or [Without Docker](../quick-setup/core/without-docker))
+
+
+
+
+:::success
+You have successfully completed the quick setup! Head over to the "Post login operations" or "Common customizations" section.
+:::
+
+
+
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/protecting-route.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/protecting-route.mdx
new file mode 100644
index 000000000..19c693a80
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/protecting-route.mdx
@@ -0,0 +1,255 @@
+---
+id: protecting-route
+title: 5. Checking for sessions in frontend routes
+hide_title: true
+---
+
+
+
+
+# 5. Checking for sessions in frontend routes
+
+Protecting a website route means that it cannot be accessed unless a user is signed in. If a non signed in user tries to access it, they will be redirected to the login page.
+
+## Sessions with Client Components
+
+Lets create a client component for the `/` route of our website.
+
+### Using the `SessionAuth` wrapper component
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ return (
+
+
+ Hello world
+
+
+ );
+}
+```
+
+`SessionAuth` is a component exposed by the SuperTokens React SDK, it checks if a session exists and if it does not exist it will redirect the user to the login page. It also does session claim checking on the frontend and take appropriate action if the claim validators fail. For example, if you have set the email verification recipe to be `"REQUIRED"`, and the user's email is not verified, this component will redirect the user to the email verification page.
+
+:::caution
+At the moment the `SessionAuth` component does not support server side rendering and will only work on the client side. On the server side, this component renders an empty screen.
+
+Refer to the next section of this page to learn how to use sessions on the server side.
+:::
+
+### Using `useSessionContext`
+
+```tsx title="app/components/homeClientComponent.tsx"
+'use client'
+
+import { useSessionContext } from "supertokens-auth-react/recipe/session"
+
+export const HomeClientComponent = () => {
+ const session = useSessionContext();
+
+ if (session.loading) {
+ return Loading...
;
+ }
+
+ if (session.doesSessionExist === false) {
+ return Session does not exist
;
+ }
+
+ return (
+
+
+
+ Client side component got userId: {session.userId}
+
+
+
+ );
+}
+```
+
+`useSessionContext` lets you access the session information on the client side using the React Context API. `session.loading` indicates if the session is currently being loaded into the context, this will also refresh the session for you if it is expired. You can use `session.doesSessionExist` to check if a valid session exists and handle it accordingly.
+
+:::info
+`useSessionContext` does not need to be used along with `SessionAuth`. Since our app is wrapped by the `SuperTokensWrapper` component, the `useSessionContext` hook can be used in any of our components.
+:::
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+## Sessions with Server Components
+
+### Creating some helper Components
+
+#### Creating a wrapper around `SessionAuth`
+Let's say we want to protect the home page of your website (`/` route). First we will create a wrapper around the `SessionAuth` component provided by SuperTokens to allow us to use it on both server side and client side.
+
+```tsx title="app/components/sessionAuthForNextJS.tsx"
+"use client";
+
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+
+type Props = Parameters[0] & {
+ children?: React.ReactNode | undefined;
+};
+
+export const SessionAuthForNextJS = (props: Props) => {
+ if (typeof window === "undefined") {
+ return props.children;
+ }
+
+ return {props.children};
+};
+```
+
+This is a client component that renders just its children on the server side and renders the children wrapped with `SessionAuth` on the client side.
+
+#### Creating the `TryRefreshComponent`
+
+This component will refresh the user's session if their current session has expired.
+
+```tsx title="app/components/tryRefreshClientComponent.tsx"
+"use client";
+
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Session from "supertokens-auth-react/recipe/session";
+import SuperTokens from "supertokens-auth-react";
+
+export const TryRefreshComponent = () => {
+ const router = useRouter();
+ const [didError, setDidError] = useState(false);
+
+ useEffect(() => {
+ /**
+ * `attemptRefreshingSession` will call the refresh token endpoint to try and
+ * refresh the session. This will throw an error if the session cannot be refreshed.
+ */
+ void Session.attemptRefreshingSession()
+ .then((hasSession) => {
+ /**
+ * If the user has a valid session, we reload the page to restart the flow
+ * with valid session tokens
+ */
+ if (hasSession) {
+ router.refresh();
+ } else {
+ SuperTokens.redirectToAuth();
+ }
+ })
+ .catch(() => {
+ setDidError(true);
+ });
+ }, []);
+
+ /**
+ * We add this check to make sure we handle the case where the refresh API fails with
+ * an unexpected error
+ */
+ if (didError) {
+ return Something went wrong, please reload the page
;
+ }
+
+ return Loading...
;
+};
+```
+
+### Using `SessionAuthForNextJS` and checking for sessions
+
+We then create a server component that can check if the session exists and return any session information we may need:
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ // `session` will be undefined if it does not exist or has expired
+ if (!session) {
+ if (!hasToken) {
+ /**
+ * This means that the user is not logged in. If you want to display some other UI in this
+ * case, you can do so here.
+ */
+ return redirect("/auth");
+ }
+
+ /**
+ * `hasInvalidClaims` indicates that session claims did not pass validation. For example if email
+ * verification is required but the user's email has not been verified.
+ */
+ if (hasInvalidClaims) {
+ /**
+ * This will make sure that the user is redirected based on their session claims. For example they
+ * will be redirected to the email verification screen if needed.
+ *
+ * We pass in no children in this case to prevent hydration issues and still be able to redirect the
+ * user.
+ */
+ return ;
+ } else {
+ /**
+ * This means that the session does not exist but we have session tokens for the user. In this case
+ * the `TryRefreshComponent` will try to refresh the session.
+ */
+ return ;
+ }
+ }
+
+ /**
+ * SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
+ * It will redirect to the login page if the session does not exist etc.
+ */
+ return (
+
+
+ Your user id is: {session.getUserId()}
+
+
+ );
+}
+```
+
+`getSSRSession` is a utility function we created in the [previous step](./session-helpers.mdx). The `TryRefreshComponent` is a client component that checks if a session exists and tries to refresh the session if it is expired.
+
+And then we can modify the `/app/page.tsx` file to use our server component
+
+```tsx title="app/page.tsx"
+declare let HomePage: any; // typecheck-only, removed from output
+import styles from './page.module.css'
+// @ts-ignore
+import { HomePage } from "./components/home";
+
+export default function Home() {
+ return (
+
+
+
+ )
+}
+```
+
+:::tip Test by navigating to `/`
+You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
+:::
+
+:::important
+An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/page.tsx).
+:::
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/server-components-requests.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/server-components-requests.mdx
new file mode 100644
index 000000000..536a7e39e
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/server-components-requests.mdx
@@ -0,0 +1,83 @@
+---
+id: server-components-requests
+title: 7. Making requests from Server Components
+hide_title: true
+---
+
+
+
+
+# 7. Making requests from Server Components
+
+Lets modify the Home page we made in a [previous step](../protecting-route.mdx) to make a call to this API
+
+```tsx title="app/components/home.tsx"
+import { NextRequest, NextResponse } from "next/server";// typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";// typecheck-only, removed from output
+import { CollectingResponse } from "supertokens-node/framework/custom";// typecheck-only, removed from output
+declare let getSSRSession: (req?: NextRequest, options?: VerifySessionOptions) => Promise<{session: SessionContainer | undefined;hasToken: boolean;hasInvalidClaims: boolean;baseResponse: CollectingResponse;nextResponse?: NextResponse;}>; // typecheck-only, removed from output
+declare let TryRefreshComponent: any; // typecheck-only, removed from output
+declare let SessionAuthForNextJS: any; // typecheck-only, removed from output
+import styles from "../page.module.css";
+import { redirect } from "next/navigation";
+// @ts-ignore
+import { getSSRSession } from "../sessionUtils";
+// @ts-ignore
+import { TryRefreshComponent } from "./tryRefreshClientComponent";
+// @ts-ignore
+import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
+
+export async function HomePage() {
+ const { session, hasToken, hasInvalidClaims } = await getSSRSession();
+
+ if (!session) {
+ if (!hasToken) {
+ return redirect("/auth");
+ }
+
+ if (hasInvalidClaims) {
+ return ;
+ } else {
+ return ;
+ }
+ }
+
+ // highlight-start
+ const userInfoResponse = await fetch('http://localhost:3000/api/user', {
+ headers: {
+ /**
+ * We read the access token from the session and use that as a Bearer token when
+ * making network requests.
+ */
+ Authorization: 'Bearer ' + session.getAccessToken(),
+ },
+ });
+
+ let message = "";
+
+ if (userInfoResponse.status === 200) {
+ message = `Your user id is: ${session.getUserId()}`
+ } else if (userInfoResponse.status === 500) {
+ message = "Something went wrong"
+ } else if (userInfoResponse.status === 401) {
+ // The TryRefreshComponent will try to refresh the session
+ return
+ } else if (userInfoResponse.status === 403) {
+ // SessionAuthForNextJS will redirect based on which claim is invalid
+ return ;
+ }
+
+ // You can use `userInfoResponse` to read the users session information
+ // highlight-end
+
+ return (
+
+
+ {message}
+
+
+ );
+}
+```
+
+We use `session` returned by `getSSRSession` to get the access token of the user. We can then send the access token as a header to the API. When the API calls `withSession` it will try to read the access token from the headers and if a session exists it will return the information. You can use the `session` object to fetch other information such as `session.getUserId()`.
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/session-helpers.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/session-helpers.mdx
new file mode 100644
index 000000000..f168b0b6a
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/session-helpers.mdx
@@ -0,0 +1,166 @@
+---
+id: session-helpers
+title: 4. Add helper functions for sessions
+hide_title: true
+---
+
+
+
+
+# 4. Add helper functions for sessions
+
+To make it easy to access session information and protect our API routes we will create some helper functions:
+
+```ts title="app/sessionUtils.ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { serialize } from "cookie";
+import { cookies, headers } from "next/headers";
+import { NextRequest, NextResponse } from "next/server";
+import Session, { SessionContainer, VerifySessionOptions } from "supertokens-node/recipe/session";
+import { PreParsedRequest, CollectingResponse } from "supertokens-node/framework/custom";
+import { HTTPMethod } from "supertokens-node/types";
+// @ts-ignore
+import { ensureSuperTokensInit } from "./config/backend";
+
+ensureSuperTokensInit();
+
+export async function getSSRSession(
+ req?: NextRequest,
+ options?: VerifySessionOptions
+): Promise<{
+ session: SessionContainer | undefined;
+ hasToken: boolean;
+ hasInvalidClaims: boolean;
+ baseResponse: CollectingResponse;
+ nextResponse?: NextResponse;
+}> {
+ const query = req !== undefined ? Object.fromEntries(new URL(req.url).searchParams.entries()) : {};
+ const parsedCookies: Record = Object.fromEntries(
+ (req !== undefined ? req.cookies : cookies()).getAll().map((cookie) => [cookie.name, cookie.value])
+ );
+
+ /**
+ * Pre parsed request is a wrapper exposed by SuperTokens. It is used as a helper to detect if the
+ * original request contains session tokens. We then use this pre parsed request to call `getSession`
+ * to check if there is a valid session.
+ */
+ let baseRequest = new PreParsedRequest({
+ method: req !== undefined ? (req.method as HTTPMethod) : "get",
+ url: req !== undefined ? req.url : "",
+ query: query,
+ headers: req !== undefined ? req.headers : headers(),
+ cookies: parsedCookies,
+ getFormBody: () => req!.formData(),
+ getJSONBody: () => req!.json(),
+ });
+
+ /**
+ * Collecting response is a wrapper exposed by SuperTokens. In this case we are using an empty
+ * CollectingResponse when calling `getSession`. If the request contains valid session tokens
+ * the SuperTokens SDK will attach all the relevant tokens to the collecting response object which
+ * we can then use to return those session tokens in the final result (refer to `withSession` in this file)
+ */
+ let baseResponse = new CollectingResponse();
+
+ try {
+ /**
+ * `getSession` will throw if session is required and there is no valid session. You can use
+ * `options` to configure whether or not you want to require sessions when calling `getSSRSession`
+ */
+ let session = await Session.getSession(baseRequest, baseResponse, options);
+ return {
+ session,
+ hasInvalidClaims: false,
+ hasToken: session !== undefined,
+ baseResponse,
+ };
+ } catch (err) {
+ if (Session.Error.isErrorFromSuperTokens(err)) {
+ return {
+ hasToken: err.type !== Session.Error.UNAUTHORISED,
+ /**
+ * This allows us to protect our routes based on the current session claims. For example
+ * this will be true if email verification is required but the user has not verified their
+ * email.
+ */
+ hasInvalidClaims: err.type === Session.Error.INVALID_CLAIMS,
+ session: undefined,
+ baseResponse,
+ nextResponse: new NextResponse("Authentication required", {
+ status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
+ }),
+ };
+ } else {
+ throw err;
+ }
+ }
+}
+
+export async function withSession(
+ request: NextRequest,
+ handler: (session: SessionContainer | undefined) => Promise,
+ options?: VerifySessionOptions
+) {
+ let { session, nextResponse, baseResponse } = await getSSRSession(request, options);
+ if (nextResponse) {
+ return nextResponse;
+ }
+
+ let userResponse = await handler(session);
+
+ let didAddCookies = false;
+ let didAddHeaders = false;
+
+ /**
+ * Base response is the response from SuperTokens that contains all the session tokens.
+ * We add all cookies and headers in the base response to the final response from the
+ * API to make sure sessions work correctly.
+ */
+ for (const respCookie of baseResponse.cookies) {
+ didAddCookies = true;
+ userResponse.headers.append(
+ "Set-Cookie",
+ serialize(respCookie.key, respCookie.value, {
+ domain: respCookie.domain,
+ expires: new Date(respCookie.expires),
+ httpOnly: respCookie.httpOnly,
+ path: respCookie.path,
+ sameSite: respCookie.sameSite,
+ secure: respCookie.secure,
+ })
+ );
+ }
+
+ baseResponse.headers.forEach((value, key) => {
+ didAddHeaders = true;
+ userResponse.headers.set(key, value);
+ });
+
+ /**
+ * For some deployment services (Vercel for example) production builds can return cached results for
+ * APIs with older header values. In this case if the session tokens have changed (because of refreshing
+ * for example) the cached result would still contain the older tokens and sessions would stop working.
+ *
+ * As a result, if we add cookies or headers from base response we also set the Cache-Control header
+ * to make sure that the final result is not a cached version.
+ */
+ if (didAddCookies || didAddHeaders) {
+ if (!userResponse.headers.has("Cache-Control")) {
+ // This is needed for production deployments with Vercel
+ userResponse.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ }
+ }
+
+ return userResponse;
+}
+```
+
+- `getSSRSession` will be used in our frontend routes to get session information when rendering on the server side. This function will:
+ - `{..., session: Object, hasToken: true}` if a session exists
+ - `{..., session: undefined, hasToken: false}` if a session does not exist
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: false}` if the session is expired
+ - `{..., session: undefined, hasToken: true, hasInvalidClaims: true}` If the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
+
+- `withSession` will be used as a session guard for each of our API routes. If a session exists it will be passed to the callback, which is where we will write our API logic. If no session exists it will pass `undefined` to the callback. This function will:
+ - Return status `401` if the session has expired
+ - Return status `403` if the session claims fail their validation. For example if email verification if required but the user's email has not been verified.
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-middleware.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-middleware.mdx
new file mode 100644
index 000000000..967c12710
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-middleware.mdx
@@ -0,0 +1,89 @@
+---
+id: session-verification-middleware
+title: Using the Next.js middleware
+hide_title: true
+---
+
+
+
+
+# Using the Next.js middleware
+
+:::important
+This method is an alternative method for using sessions in an API. If you are already using [session guards](./session-verification-session-guard.mdx), you can skip this step.
+:::
+
+## Setting up the middleware
+
+In the middleware we check if a session exists using the `withSession` helper function we created [here](./session-helpers.mdx) and set the user's user id to the request headers using the session object. You can set other information in the same way.
+
+:::caution
+You cannot pass the full session container through the middleware because the Next.js middleware does not allow objects to be passed. If you need to access the full session container in your APIs switch to using [session guards](./session-verification-session-guard.mdx).
+:::
+
+```tsx title="middleware.tsx"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse } from 'next/server'
+import type { NextRequest } from 'next/server'
+import { SessionContainer } from 'supertokens-node/recipe/session'
+// @ts-ignore
+import { withSession } from './app/sessionUtils';
+
+
+export async function middleware(
+ request: NextRequest & { session?: SessionContainer }
+) {
+ if (request.headers.has("x-user-id")) {
+ console.warn("The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.");
+ request.headers.delete("x-user-id");
+ }
+
+ if (request.nextUrl.pathname.startsWith('/api/auth')) {
+ /**
+ * /api/auth/* endpoints are exposed by the SuperTokens SDK,
+ * we do not want to modify the request for these routes
+ */
+ return NextResponse.next()
+ }
+
+ return withSession(request, async (session) => {
+ if (session === undefined) {
+ return NextResponse.next()
+ }
+ return NextResponse.next({
+ headers: {
+ // You cannot attach the full session object here
+ 'x-user-id': session.getUserId(),
+ },
+ })
+ })
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+## Fetching the user ID in your APIs
+
+The middleware will run for all routes, we can read information set by the middleware in the API routes:
+
+```tsx title="app/api/userid/route.ts"
+import { NextResponse, NextRequest } from "next/server";
+
+export function GET(request: NextRequest) {
+ const userId = request.headers.get("x-user-id");
+
+ // The middleware only adds the userId if a session exists
+ if (userId === null) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ userId,
+ });
+}
+```
+
+This creates a `GET` request for the `/api/userid` route which returns the user id of the currently logged in user.
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-session-guard.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-session-guard.mdx
new file mode 100644
index 000000000..5b64f688a
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/session-verification-session-guard.mdx
@@ -0,0 +1,50 @@
+---
+id: session-verification-session-guard
+title: Adding a session guard to each API route
+hide_title: true
+---
+
+
+
+
+# Adding a session guard to each API route
+
+:::note
+This is applicable for when the frontend calls an API in the `/app/api` folder.
+:::
+
+For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
+
+Create a new file `/app/api/user/route.ts`
+
+- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/app/api/user/route.ts).
+
+```ts title="app/api/user/route.ts"
+declare let withSession: (request: NextRequest,handler: (session: SessionContainer | undefined) => Promise,options?: VerifySessionOptions) => void; // typecheck-only, removed from output
+import { SessionContainer, VerifySessionOptions } from 'supertokens-node/recipe/session' // typecheck-only, removed from output
+import { NextResponse, NextRequest } from "next/server";
+import SuperTokens from "supertokens-node";
+// @ts-ignore
+import { withSession } from "../../sessionUtils";
+
+export function GET(request: NextRequest) {
+ return withSession(request, async (session) => {
+ if (!session) {
+ return new NextResponse("Authentication required", { status: 401 });
+ }
+
+ return NextResponse.json({
+ note: "Fetch any data from your application for authenticated user after using verifySession middleware",
+ userId: session.getUserId(),
+ sessionHandle: session.getHandle(),
+ accessTokenPayload: session.getAccessTokenPayload(),
+ });
+ });
+}
+```
+
+In the above snippet we are creating a `GET` handler for the `/api/user` route. We call the `withSession` helper function we created in a [previous step](./session-helpers.mdx), the function will pass the session object in the callback which we then use to read user information. If a session does not exist `undefined` will be passed intead.
+
+The `withSession` guard will return:
+- Status `401` if the session does not exist or has expired
+- Stauts `403` if the session claims fail their validation. For example if email verification is required but the user's email is not verified.
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-backend.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-backend.mdx
new file mode 100644
index 000000000..6beea3b80
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-backend.mdx
@@ -0,0 +1,82 @@
+---
+id: setting-up-backend
+title: 3. Adding auth APIs
+hide_title: true
+---
+
+
+
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import AppInfoForm from "/src/components/appInfoForm"
+
+# 3. Adding auth APIs
+
+We will add all the backend APIs for auth on `/api/auth`. This can be changed by setting the `apiBasePath` property in the `appInfo` object in the `appInfo.ts` file. For the rest of this page, we will assume you are using `/api/auth`.
+
+## 1) Create the API folder
+- Be sure to create the `auth` folder in the `app/api/` folder.
+- `[[...path]].tsx` will use the `getAppDirRequestHandler` helper function exposed by `supertokens-node` which helps in calling all the APIs like sign in, sign up etc. (the full folder path should be `/app/api/auth/[[...path]].tsx`).
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/api/auth/%5B...path%5D).
+
+## 2) Expose the SuperTokens APIs
+
+
+
+```tsx title="app/api/auth/[[...path]].ts"
+declare let ensureSuperTokensInit: () => void; // typecheck-only, removed from output
+import { getAppDirRequestHandler } from 'supertokens-node/nextjs';
+import { NextRequest, NextResponse } from 'next/server';
+// @ts-ignore
+import { ensureSuperTokensInit } from '../../../config/backend';
+
+ensureSuperTokensInit();
+
+const handleCall = getAppDirRequestHandler(NextResponse);
+
+export async function GET(request: NextRequest) {
+ const res = await handleCall(request);
+ if (!res.headers.has('Cache-Control')) {
+ // This is needed for production deployments with Vercel
+ res.headers.set(
+ 'Cache-Control',
+ 'no-cache, no-store, max-age=0, must-revalidate'
+ )
+ }
+ return res;
+}
+
+export async function POST(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function DELETE(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PUT(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function PATCH(request: NextRequest) {
+ return handleCall(request);
+}
+
+export async function HEAD(request: NextRequest) {
+ return handleCall(request);
+}
+```
+
+:::note
+In the snippet above we add the `Cache-Control` header to the responses for all auth APIs with the `GET` method. This is required if you are deploying your app with Vercel because API responses are automatically cached for production deployments. This results in problems because APIs such as `/session/refresh` return older session tokens resulting in infinite calls to refresh if an API returns unauthorised status. Setting the header ensures that Vercel does not cache any of the auth API responses.
+:::
+
+
+
+## 3) Use the login widget
+If you are now able to sign in or sign up, this means the backend setup is done correctly! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
diff --git a/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-frontend.mdx b/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-frontend.mdx
new file mode 100644
index 000000000..635a11d76
--- /dev/null
+++ b/v2/thirdpartypasswordless/nextjs/app-directory/setting-up-frontend.mdx
@@ -0,0 +1,72 @@
+---
+id: setting-up-frontend
+title: 2. Showing the Login UI
+hide_title: true
+show_ui_switcher: true
+---
+
+
+
+
+import {
+ PreBuiltOrCustomUISwitcher,
+ PreBuiltUIContent,
+ CustomUIContent,
+} from "/src/components/preBuiltOrCustomUISwitcher";
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import AppInfoForm from "/src/components/appInfoForm";
+
+# 2. Showing the Login UI
+
+
+
+
+
+## 1) Create the `app/auth/[[...path]].tsx` page
+- Be sure to create the `auth` folder in the `app` folder.
+- `[[...path]].tsx` will contain the component for showing SuperTokens UI
+- An example of this can be found [here](https://github.com/supertokens/next.js/tree/canary/examples/with-supertokens/app/auth/%5B%5B...path%5D%5D).
+
+## 2) Create the `Auth` component:
+
+```tsx title="app/auth/[[...path]].tsx"
+'use client';
+
+import { useEffect } from 'react';
+import { redirectToAuth } from 'supertokens-auth-react';
+import SuperTokens from 'supertokens-auth-react/ui';
+import { ^{recipePreBuiltUINameCapitalLetters} } from "supertokens-auth-react/recipe/^{codeImportRecipeName}/prebuiltui";
+
+export default function Auth() {
+ // if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
+ useEffect(() => {
+ if (
+ SuperTokens.canHandleRoute([^{recipePreBuiltUINameCapitalLetters}]) === false
+ ) {
+ redirectToAuth({ redirectBack: false });
+ }
+ }, []);
+
+ if (typeof window !== 'undefined') {
+ return SuperTokens.getRoutingComponent([^{recipePreBuiltUINameCapitalLetters}]);
+ }
+
+ return null;
+}
+```
+
+## 3) Visit `/auth` page on your website
+
+If you see a login UI, then you have successfully completed this step! If not, please feel free to ask questions on [Discord](https://supertokens.com/discord)
+
+
+
+
+
+You need to build your own UI. Please follow the docs after the "Initialisation" section in the "Using your own UI" section for how to build out the various auth flows.
+
+
+
+
diff --git a/v2/thirdpartypasswordless/nextjs/init.mdx b/v2/thirdpartypasswordless/nextjs/init.mdx
index 2650118e5..8f60e64aa 100644
--- a/v2/thirdpartypasswordless/nextjs/init.mdx
+++ b/v2/thirdpartypasswordless/nextjs/init.mdx
@@ -36,7 +36,6 @@ yarn add supertokens-node supertokens-auth-react supertokens-web-js nextjs-cors
- Create an `appInfo.ts` inside the `config` folder.
- Create a `backendConfig.ts` inside the `config` folder.
- Create a `frontendConfig.ts` inside the `config` folder.
-- An example of these files can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/config/).
## 3) Create the `appInfo` configuration.
@@ -227,7 +226,6 @@ export const backendConfig = (): TypeInput => {
## ^{nextjsinitlastnumber}) Call the frontend `init` functions and wrap with `` component
- Create a `/pages/_app.tsx` file. You can learn more about this file [here](https://nextjs.org/docs/advanced-features/custom-app).
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx)
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdpartypasswordless/nextjs/protecting-route.mdx b/v2/thirdpartypasswordless/nextjs/protecting-route.mdx
index 03e6187c7..21505368e 100644
--- a/v2/thirdpartypasswordless/nextjs/protecting-route.mdx
+++ b/v2/thirdpartypasswordless/nextjs/protecting-route.mdx
@@ -38,10 +38,6 @@ export default function Home() {
}
```
-:::important
-An example of this can be seen [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L36).
-:::
-
:::tip Test by navigating to `/`
You should be redirected to the login page. After that, sign in, and then visit `/` again. This time, there should be no redirection.
:::
diff --git a/v2/thirdpartypasswordless/nextjs/session-verification/in-api.mdx b/v2/thirdpartypasswordless/nextjs/session-verification/in-api.mdx
index a8220ae96..e0d57c781 100644
--- a/v2/thirdpartypasswordless/nextjs/session-verification/in-api.mdx
+++ b/v2/thirdpartypasswordless/nextjs/session-verification/in-api.mdx
@@ -18,7 +18,6 @@ This is applicable for when the frontend calls an API in the `/pages/api` folder
For this guide, we will assume that we want an API `/api/user GET` which returns the current session information.
## 1) Create a new file `/pages/api/user.ts`
-- An example of this is [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/user.ts).
## 2) Call the `supertokens.init` function
Remember that whenever we want to use any functions from the `supertokens-node` lib, we have to call the `supertokens.init` function at the top of that serverless function file.
diff --git a/v2/thirdpartypasswordless/nextjs/session-verification/in-ssr.mdx b/v2/thirdpartypasswordless/nextjs/session-verification/in-ssr.mdx
index e33b15cf2..4e7a8cdb0 100644
--- a/v2/thirdpartypasswordless/nextjs/session-verification/in-ssr.mdx
+++ b/v2/thirdpartypasswordless/nextjs/session-verification/in-ssr.mdx
@@ -24,8 +24,6 @@ For this guide, we will assume that we want to pass the logged in user's ID as a
If using `getInitialProps`, the method described below applies as well. The only difference is the way the props are returned (see comments in the code).
:::
-An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/index.tsx#L15).
-
```tsx
import Session from 'supertokens-node/recipe/session'
@@ -90,7 +88,6 @@ Do not use the `verifySession` function here. The reason is that this will send
- The following will refresh a session if needed, for all your website pages
- This goes in the `/pages/_app.tsx` file
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/_app.tsx#L16).
```tsx title="/pages/_app.tsx"
diff --git a/v2/thirdpartypasswordless/nextjs/setting-up-backend.mdx b/v2/thirdpartypasswordless/nextjs/setting-up-backend.mdx
index 89c0d6321..3658e19f8 100644
--- a/v2/thirdpartypasswordless/nextjs/setting-up-backend.mdx
+++ b/v2/thirdpartypasswordless/nextjs/setting-up-backend.mdx
@@ -18,7 +18,6 @@ We will add all the backend APIs for auth on `/api/auth`. This can be changed by
## 1) Create the `pages/api/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages/api/` folder.
- `[[...path]].tsx` will use the middleware exposed by `supertokens-node` which exposes all the APIs like sign in, sign up etc..
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/api/auth/%5B%5B...path%5D%5D.ts).
## 2) Expose the SuperTokens APIs
diff --git a/v2/thirdpartypasswordless/nextjs/setting-up-frontend.mdx b/v2/thirdpartypasswordless/nextjs/setting-up-frontend.mdx
index f1ff8f414..9f7cf1295 100644
--- a/v2/thirdpartypasswordless/nextjs/setting-up-frontend.mdx
+++ b/v2/thirdpartypasswordless/nextjs/setting-up-frontend.mdx
@@ -27,7 +27,6 @@ import AppInfoForm from "/src/components/appInfoForm";
## 1) Create the `pages/auth/[[...path]].tsx` page
- Be sure to create the `auth` folder in the `pages` folder.
- `[[...path]].tsx` will contain the component for showing SuperTokens UI
-- An example of this can be found [here](https://github.com/supertokens/next.js/blob/canary/examples/with-supertokens/pages/auth/%5B%5B...path%5D%5D.tsx).
## 2) Create the `Auth` component:
diff --git a/v2/thirdpartypasswordless/sidebars.js b/v2/thirdpartypasswordless/sidebars.js
index 62a2c49ef..e21bab01c 100644
--- a/v2/thirdpartypasswordless/sidebars.js
+++ b/v2/thirdpartypasswordless/sidebars.js
@@ -177,20 +177,48 @@ module.exports = {
logoUrl: '/img/logos/next-logo.png'
},
items: [
- "nextjs/about",
- "nextjs/init",
- "nextjs/setting-up-frontend",
- "nextjs/setting-up-backend",
- "nextjs/protecting-route",
{
type: 'category',
- label: '5. Session verification',
+ label: 'Using the App directory',
items: [
- "nextjs/session-verification/in-api",
- "nextjs/session-verification/in-ssr"
+ "nextjs/app-directory/about",
+ "nextjs/app-directory/init",
+ "nextjs/app-directory/setting-up-frontend",
+ "nextjs/app-directory/setting-up-backend",
+ "nextjs/app-directory/session-helpers",
+ "nextjs/app-directory/protecting-route",
+ {
+ type: "category",
+ label: "6. Checking for sessions in API routes",
+ items: [
+ "nextjs/app-directory/session-verification-session-guard",
+ "nextjs/app-directory/session-verification-middleware",
+ ],
+ },
+ "nextjs/app-directory/server-components-requests",
+ "nextjs/app-directory/next-steps"
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Using the Pages directory',
+ items: [
+ "nextjs/about",
+ "nextjs/init",
+ "nextjs/setting-up-frontend",
+ "nextjs/setting-up-backend",
+ "nextjs/protecting-route",
+ {
+ type: 'category',
+ label: '5. Session verification',
+ items: [
+ "nextjs/session-verification/in-api",
+ "nextjs/session-verification/in-ssr"
+ ],
+ },
+ "nextjs/next-steps"
],
},
- "nextjs/next-steps"
],
},
{