/
Contact usSee pricingStart building

    About B2B Saas Authentication

    Introduction
    Stytch B2B Basics
    Integration Approaches
      Full-stack overview
      Frontend (pre-built UI)
      Frontend (headless)
      Backend
    Next.js
      Routing
      Authentication
      Sessions
    Migrations
      Overview
      Reconciling data models
      Migrating user data
      Additional migration considerations
      Zero-downtime deployment
      Defining external IDs for members
      Exporting from Stytch
    Custom Domains
      Overview

    Authentication

    Single Sign On
    • Resources

      • Overview
        External SSO Connections
        Standalone SSO
    • Integration Guides

      • Start here
        Backend integration guide
        Headless integration guide
        Pre-built UI integration guide
    OAuth
    • Resources

      • Overview
        Authentication flows
        Identity providers
        Google One Tap
        Provider setup
    • Integration Guides

      • Start here
        Backend integration
        Headless frontend integration
        Pre-built UI frontend integration
    Connected AppsBeta
      Setting up Connected Apps
      About Remote MCP Servers
    • Resources

      • Integrate with AI agents
        Integrate with a remote MCP server
    Sessions
    • Resources

      • Overview
        JWTs vs Session Tokens
        How to use Stytch JWTs
        Custom Claims
    • Integration Guides

      • Start here
        Backend integration
        Frontend integration
    Email OTP
      Overview
    Magic Links
    • Resources

      • Overview
        Email Security Scanner Protections
    • Integration Guides

      • Start here
        Backend integration
        Headless frontend integration
        Pre-built UI frontend integration
    Multi-Factor Authentication
    • Resources

      • Overview
    • Integration Guides

      • Start here
        Backend integration
        Headless frontend integration
        Pre-built UI frontend integration
    Passwords
      Overview
      Strength policies
    UI components
      Overview
      Implement the Discovery flow
      Implement the Organization flow
    DFP Protected Auth
      Overview
      Setting up DFP Protected Auth
      Handling challenges
    M2M Authentication
      Authenticate an M2M Client
      Rotate client secrets
      Import M2M Clients from Auth0

    Authorization & Provisioning

    RBAC
    • Resources

      • Overview
        Stytch Resources & Roles
        Role assignment
    • Integration Guides

      • Start here
        Backend integration
        Headless frontend integration
    SCIM
    • Resources

      • Overview
        Supported actions
    • Integration Guides

      • Using Okta
        Using Microsoft Entra
    Organizations
      Managing org settings
      JIT Provisioning

    Testing

    E2E testing
    Sandbox values
Get support on SlackVisit our developer forum

Contact us

B2B Saas Authentication

/

Guides

/

About B2B Saas Authentication

/

Next.js

/

Sessions

Session management

Once a Member successfully authenticates, a Stytch Session will be minted and returned in the API response.

Most applications will use a combination of frontend and backend session management; both are discussed below.

Frontend

Storing session cookies

Whether you’re using our frontend or backend SDK for the authentication flow, you’ll want to store the Stytch Session on your frontend.

If you’re using our Next.js SDK for authentication flows on the frontend, session cookies will be automatically stored in the browser, and sent along to your backend (as long as they share a domain). More information and example code snippets can be found in our frontend SDK documentation here.

Managing application state with hooks

Our Next.js SDK offers Member and Session hooks that represent the current state of a Stytch Member or Stytch Session.

These hooks return envelope objects:

// Get the state of the Member object
const {member, fromCache, isInitialized} = useStytchMember();
// Get the state of the Session object
const {session, fromCache, isInitialized} = useStytchMemberSession();

These envelope objects represent the state of these objects as they relate to SWR (Stale-While-Revalidating). In particular:

  • In SSR/SSG contexts, as well as the first client side render, member and session will be null and isInitialized will be false.
  • The SDK will read member and session out of persistent storage, and rerender with fromCache: true - at this point you’re reading the stale-while-revalidating value.
  • The SDK will make network requests to pull the most up-to-date user and session objects, and serve them with fromCache: false- at this point, the SDK has updated the cached data.

A common pattern is to use these hook values to determine application behavior - for instance:

import React, { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useStytchUser } from '@stytch/nextjs/b2b';

export default function Profile() {
  const router = useRouter();
  const { session, isInitialized } = useStytchMemberSession();

  useEffect(() => {
    // Redirect to the login page if the Session is null (e.g. no active Session)
    if (isInitialized && session === null) {
      router.push('/login');
    }
  }, [session, isInitialized]);

  return (
    <Layout>
      <h1>Your Profile</h1>
      <pre>{JSON.stringify(member, null, 2)}</pre>
    </Layout>
  );
}

Backend

Storing session cookies

If you’re not using our Next.js SDK, and are using a backend-only integration you’ll need to store session cookies on your frontend yourself. Next.js has documentation on how to do this here.

Protecting backend resources

Even with a frontend integration, you’ll want to add session authentication to any backend routes you’d like to gate behind authentication.

There are a few different strategies for this that Next.js covers in their documentation.

The examples below utilize our Node SDK since these are strategies for authenticating a Stytch Member on the server side.

For information on supported runtime contexts, see this section of our Node SDK README.

Next.js has documentation on route handler authentication strategies here.

The below is an example of enforcing authentication on a specific route via a route handler and Stytch Session Token authentication.

app/api/my_protected_route.ts

import type { NextApiRequest, NextApiResponse } from 'next';
import loadStytch from '../../lib/loadStytch';
import Cookies from 'cookies';

type ErrorData = {
  errorString: string;
};

export async function handler(req: NextApiRequest, res: NextApiResponse<ErrorData>) {
  // Get session from cookie
  const cookies = new Cookies(req, res);
  const session = cookies.get('stytch_session');
  // If session does not exist display an error
  if (!session) {
    return res.status(400).json({ errorString: 'No session provided' });
  }
  try {
    const stytchClient = new stytch.B2BClient({
      project_id: process.env.STYTCH_PROJECT_ID || '',
      secret: process.env.STYTCH_SECRET || '',
    });
    // Validate Stytch session
    await stytchClient.sessions.authenticate({ session_token: session });
    // Request is authenticated - safe to fetch/return data for authorized users
    console.log("This request is authenticated!")
    return res.status(200).end();
  } catch (error) {
    const errorString = JSON.stringify(error);
    return res.status(400).json({ errorString });
  }
}

export default handler;

Next.js has documentation on middleware authentication strategies here.

The below snippet is an example of a middleware.ts file that utilizes Stytch JWTs for authentication.

middleware.ts

import { NextRequest, NextResponse } from 'next/server';
import * as stytch from 'stytch';
import { cookies } from 'next/headers';

export default async function middleware(req: NextRequest) {
  const path = req.nextUrl.pathname;
  // If this is an authentication request, continue.
  if (path === '/authenticate') return NextResponse.next();

  const sessionJwt = cookies().get('stytch_session_jwt')?.value;
  // If no session is present, redirect to authentication flow.
  if (!sessionJwt) return NextResponse.redirect(new URL('/login', req.nextUrl));

  const stytchClient = new stytch.B2BClient({
      project_id: process.env.STYTCH_PROJECT_ID || '',
      secret: process.env.STYTCH_SECRET || '',
    });

  // authenticateJwt() will attempt to authenticate the Stytch JWT locally first, then, if that fails for any reason, will hit the Stytch API as a fallback.
  try {
    await stytchClient.sessions.authenticateJwt({
      session_jwt: sessionJwt
    });
  }
  catch (e) {   // If the session is not valid, redirect to authentication flow.
    return NextResponse.redirect(new URL('/login', req.nextUrl));
  }
}

// Routes that do not require authentication checks. 
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
}

Next.js has documentation on middleware authentication strategies here.

The snippets below are pulled from one of our demo applications - source code here.

In src/app/shared-actions.ts, getStytchUser() authenticates the current session stored in cookies, redirecting to / if there is no session. This is the shared server action that can be used to gate an action behind authentication.

In src/app/get-code/actions.tsx, getStytchUser() is used to gate the action (saving a photo) behind Stytch User authentication.

src/app/shared-actions.ts

export async function getStytchUser() {
  const cookieStore = cookies();
  const sessionCookie = cookieStore.get("stytch_session");

  if (!sessionCookie) {
    redirect("/");
  }

  let session;
  try {
    session = await stytch.sessions.authenticate({
      session_token: sessionCookie?.value,
    });
  } catch (error) {
    // log error
  }

  return session.user;
}

Example usage in src/app/get-code/actions.tsx:

export async function saveUserToPhotoAction(
  previousState: FormState,
  formData: FormData,
) {
  const user = await getStytchUser();

  const code = formData.get("code") as string;

  // ...

  redirect("/profile");
}

Frontend

Storing session cookies

Managing application state with hooks

Backend

Storing session cookies

Protecting backend resources