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 NextJS 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 NextJS 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 NextJS SDK, and are using a backend-only integration you’ll need to store session cookies on your frontend yourself. NextJS 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 NextJS covers in their documentation.

Here’s an example of securing a route handler with Stytch:

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 (!storedSession) {
    return res.status(400).json({ errorString: 'No session provided' });
  }
  try {
    const stytchClient = new stytch.Client({
      project_id: process.env.STYTCH_PROJECT_ID || '',
      secret: process.env.STYTCH_SECRET || '',
      env: process.env.STYTCH_PROJECT_ENV === 'live' ? stytch.envs.live : stytch.envs.test,
    });
    // Validate Stytch session
    await stytchClient.sessions.authenticate({ session_token: storedSession });
    // 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;