/
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

/

Integration Approaches

/

Backend

Stytch and backend development

Our backend API and SDKs integrate tightly with your application's server-side logic for maximum code control and flexibility. Because of its API-first design, Stytch’s backend integration enables you to customize and control auth flows with precision. This guide covers the fundamental aspects and key considerations when implementing Stytch on your backend.

Here’s a list of libraries and options we offer for backend development:

  • Backend API
  • Backend SDKs
    • Go SDK
    • Python SDK
    • Node.js SDK
    • Ruby SDK
    • Java SDK

Refer to the backend API reference page, where you can select the language and backend SDK of your preference, for full documentation. You can also explore the example apps to get hands-on with the code.

Overview

Backend diagram

At a high-level, implementing Stytch server-side involves the following steps:

  1. Your backend collects all necessary authentication data (e.g., IDs, tokens, emails, and metadata) and calls the Stytch API to perform a specific auth related operation (e.g., initiate an auth flow, retrieve an organization or member record, and refresh a session).
  2. Stytch API processes the request and returns a response with pertinent data (e.g., minted session, organization data, auth metadata, and statuses).
  3. Your backend handles the response and transforms the data as needed, which may involve calling the Stytch API again, passing the data to a different backend or microservice, or relaying data back to your frontend.

As the most feature-complete and flexible option, our backend API and SDKs enable you to tightly integrate Stytch's auth primitives with your application's logic. However, this level of control and customization generally requires you to write more application code.

Code examples

Here are some example code snippets that demonstrate the general idea of implementing Stytch on the backend.

Authentication flows

const stytch = require('stytch');
const stytchB2BClient = new stytch.B2BClient({
  project_id: "PROJECT_ID"
  secret: "SECRET",
});

// Start the authentication flow
app.post("/login-or-signup", async function (req, res) {
  try {
    const params = { 
      email: req.body.email, 
      organization_id: req.body.organization_id 
    };
    const resp = await stytchB2BClient.magicLinks.email.loginOrSignup(params);
    res.status(200).end();
  } catch (err) {
    console.error(err);
    res.status(400).send('Authentication failed');
 }
});

// Complete the authentication flow which mints the session
app.get("/authenticate", async function (req, res) {
  try {
    const params = { 
      token: req.query.token, 
      session_duration_minutes: 60 
    };
    const resp = await stytchB2BClient.magicLinks.authenticate(params);
    res.cookie("stytch_session_jwt", resp.session_jwt);
    res.redirect('/dashboard');
  } catch (err) {
    console.error(err);
    res.status(401).send('Authentication failed');
 }
});
...

Session management

// Authenticate the session  
async function isAuthenticated(req, res, next) {
  try {
    const sessionJWT = req.cookies.stytch_session_jwt;
    const resp = await stytchB2BClient.sessions.authenticateJWT({session_jwt: sessionJWT});
    req.stytchMember = resp.member;
    next();
  } catch (err) {
    console.error(err);
    res.status(401).send('Authentication failed');
  } 
}

// Protect a route
app.get('/dashboard', isAuthenticated, (req, res) => {
  res.send('Welcome to your dashboard');
});

// Revoke a session
app.get('/logout', async (req, res) => {
  try {
    const sessionJWT = req.cookies.stytch_session_jwt;
    const logout = await stytchB2BClient.sessions.revoke({session_jwt: sessionJWT});
    res.clearCookie("stytch_session_jwt");
    res.redirect('/login');
  } catch (err) {
    console.error(err);
    res.status(400).end();
  }
});
...

Organization and member management

// Update member record
app.put('/organization', isAuthenticated, async (req, res) => {
  try { 
    const params = {
      organization_id: req.stytchMember.organization.organization_id,
      organization_name: 'Customer A',
      mfa_policy: 'REQUIRED_FOR_ALL',
      email_allowed_domains: '@customer-a.com',
      email_invite: 'RESTRICTED',
      email_jit_provisioning: 'RESTRICTED'
    };
    const resp = await stytchB2BClient.organizations.update(params);
    // Update user record in your database
    res.status(200).end();
  } catch (err) {
    console.error(err);
    res.status(401).end();    
  }
});
...
// Update member record
app.put('/profile', isAuthenticated, async (req, res) => {
  try { 
    const params = {
      untrusted_metadata: {
         profile_pic_url: req.body["profile_pic_url"],
         display_name: req.body["display_name"]
      },
      trusted_metadata: {
	      billing_address: req.body["billing_address"]
      }
    };
    const resp = await stytchB2BClient.organizations.member.update(req.stytchMember.member_id);
    // Update user record in your database
    res.status(200).end();
  } catch (err) {
    console.error(err);
    res.status(401).end();    
  }
});
...

Considerations when using our backend API and SDKs

Hydrating sessions on the frontend

If you’re authenticating end users and minting sessions on the backend with Stytch, you can hydrate sessions on your frontend by setting the cookie server-side with the corresponding session_jwt or session_token.

const resp = await stytchB2BClient.magicLinks.authenticate(params);
// Set cookie with the newly minted Stytch session to pass on to your frontend
res.cookie("stytch_session_jwt", resp.session_jwt);
res.cookie("stytch_session", resp.session_token);

If you’re also using our frontend SDKs for session management, you have two options for passing the server-side session into our frontend SDK:

  1. You can set the cookies directly in a similar manner to the code above. It's important to correctly set the cookie names as stytch_session_jwt and stytch_session (or whatever you customized their names to be) and call the sessions.authenticate() method. Our frontend SDKs will then use the new values from these cookies, overwriting any session cookies it might’ve generated previously, and proceed to manage the backend-created session as expected.
  2. We recommend you use the frontend SDK sessions.updateSession method.
stytchB2BClient.session.updateSession({
  session_token: 'a session token from your backend',
  session_jwt: 'a session JWT from your backend',
});

You can read more about session hydration here.

Keeping Stytch and your database in sync

Stytch serves as a datastore for your organizations' and members' identity records (e.g., email addresses, phone numbers, metadata, and auth registrations), which you can access via our organization and member management endpoints like the Get Organization endpoint and the Get Member endpoint. Moreover, Stytch allows you to moderately extend Organization and Member records with metadata fields that can store custom JSON data specific to your application – which is particularly useful for session authentication and authorization decisions.

However, most applications have their own primary database to store their end users' account data. We recommend storing Stytch organization_ids and member_ids in that database in order to associate your internal accounts with their corresponding Stytch Organizations and Members. Upon receiving a success response from Stytch’s API, your backend should create a new end user record or update an existing one in your database when applicable.

What's next

If you have additional questions about our different integration options, please feel free to reach out to us in our community Slack, our developer forum, or at support@stytch.com for further guidance.

Overview

Code examples

Authentication flows

Session management

Organization and member management

Considerations when using our backend API and SDKs

Hydrating sessions on the frontend

Keeping Stytch and your database in sync

What's next