B2B Saas Authentication

/

Guides

/

About B2B Saas Authentication

/

Migrations

/

Reconciling data models

Reconciling data models

The first step of planning your migration to Stytch is planning out how you want to connect your current data model to Stytch's core entities. This guide outlines the key considerations and approaches for how to do this for a range of existing data models.

Overview of Stytch's data model

Stytch's B2B data model is centered around two first-class API entities: Organizations and Members.

  1. A Stytch Organization is the top-level “tenant", which groups one or more Members together within your application.
  2. A Stytch Member is an end user who belongs to an Organization. Stytch uses email address as the primary unique identifier for Members within an Organization. An end user can belong to multiple Organizations by having multiple Member records, which are linked together by using the same email address.
B2B data modelStytch's B2B data model treats Organizations and Members as core data entities.

For more details and technical specifics on Organizations and Members, visit our B2B Overview or the API reference.


Defining the top-level tenant

The top-level tenant of your application usually maps to your business customers, who pay for your service and own all the data and resources within their instance. Key characteristics of a top-level tenant are:

  • Account Ownership: the tenant holds the subscription or contract for using your services, or has the ability to manage billing and upgrade if you have a free tier
  • Access Management: the tenant determines which end users can access their instance, and what roles and permissions authorized end users can do within the context of the tenant
  • User Management: the tenant can manage end users, performing admin actions like updating emails or resetting MFA enrollment
  • Data Segregation: the data and configurations that belong to the tenant are typically isolated from other tenants, ensuring strong governance and security

The top-level tenant you've identified will map to Stytch's Organization concept.

To create a clean 1:1 mapping between your internal representation of the top-level tenant and Stytch's Organization, store the stable Stytch organization_id as a column on your equivalent entity.

Outside of the UUID, Stytch Organizations can also be uniquely identified by organization_slug, which is the unique URL identifier of your application (e.g. acme for acme.your-app.com or your-app.com/team/acme). However, as the organization slug can be updated, we recommend primarily using the organization_id in any internal references to the Stytch object.

If you have internal information about the Organization that you want to have accessible in Stytch (for example, to automatically include in the JWT Custom Claims for Member Sessions), you can use the trusted_metadata field on the Organization.

Stytch supports a wide range of authentication and provisioning settings that you can offload entirely to Stytch, to control approved authentication methods, MFA Policies, Just-in-Time (JIT) Provisioning and more. Refer to the Organization object in the API reference to see all available fields and settings. You can set these while migrating Organizations in via the CreateOrganization method.

[
  {
    "organization_id": "organization-test-07971b...",
    "organization_name": "Team A",
    "organization_slug": "team-a",
    "trusted_metadata": {
      "billing_tier": "free",
      "privacy_setting": "public"
    },
    "email_invites": "ALL_ALLOWED",
    "email_jit_provisioning": "NOT_ALLOWED",
    ...
  }, 
  {
    "organization_id": "organization-test-02645e...",
    "organization_name": "Team B",
    "organization_slug": "team-b",
    "trusted_metadata": {
      "billing_tier": "premium",
      "privacy_setting": "private"
    },
  	"email_invites": "RESTRICTED",
    "email_jit_provisioning": "RESTRICTED",
    "email_allowed_domains": ["stytch.com"],
    ...
  },
  {
    "organization_id": "organization-test-09320h...",
    "organization_name": "Team C",
    "organization_slug": "team-c",
    "trusted_metadata": {
      "billing_tier": "enterprise",
      "privacy_setting": "private"
    },
    "auth_methods": "RESTRICTED",
    "allowed_auth_methods": ["sso"],
    ...
  }
]

Defining & mapping end users

Stytch's user entity is the Member object, which is scoped to a specific Organization and is uniquely identified within that Organization by their email address. If claude.shannon@stytch.com belongs to three different Organizations, there will be three entirely distinct Member records associated with claude.shannon@stytch.com.

End users can still "switch" between different Organizations without having to log out and log back in, but this data model ensures the data isolation expected by enterprise companies, and allows each Organization to have complete control over the end users who are accessing their application.

Depending on how your application enforces and stores the relationships between users and groups, you will need to create one or many Stytch Member objects for every application user.

Migrating from 1:1 data model

If your application already defines an end user as belonging to a single Organization, you will create one Member record for each existing user record in your system. Store the stable Stytch member_id on your internal representation of the user for easy queries.

For applications where the 1:1 data model is global, and an end user can only belong to one Organization at a time, keep in mind that Stytch does not have this restriction and is more of a "many 1:1 model". If your application relies on the assumption that a single email will only ever be associated with a single Organization, you will need to add in your own enforcement of this constraint before calling Stytch.

While we do recommend removing this restriction, as it can cause unnecessary friction for contractors or companies with multiple instances of your application, it is not necessary to do as part of your migration.

Migrating from 1:many data model

If your application allows a single User record to be shared across multiple Organizations, that all reference the same UserID, you will create multiple Member objects for each User in your system -- one for each Organization that the end user is shared across.

If you already have a membership table storing the relationship between User<>Organizations, you can add the Stytch member_ids to that record. However, keep in mind that in Stytch changing the email or name of one Member object will not impact the other Member records that share the original email and so it is important to keep this table in sync and/or ensure that all AuthN/AuthZ functionality looks to Stytch as the source of truth rather than this table.

A fairly common approach with customer is to migrate to Stytch with their existing data model in place leveraging a mapping table like the one described above, and then later on update their internal data model to be more consistent with an organization-tenancy model, improving the security and data governance controls for their enterprise customers.

Regardless of either scenario, you can leverage the following features to enrich the Stytch Member object:

  • Custom metadata: Utilize the custom trusted_metadata and untrusted_metadata fields on the Member object to store any application or business-specific attributes for your end user and their membership.
  • Authentication and authorization settings: Configure a Member's auth settings to control MFA enrollment, breakglass privileges, and roles and permissions.

Refer to the Member object in the API reference to see all available fields and settings.

[
  // These three Member objects are all the same end user
  {
    "member_id": "member-test-32fc...",
    "organization_id": "organization-test-07971...",
    "email_address": "adalovelace@stytch.com",
    "email_address_verified": true,
    "name": "Ada Lovelace",
    "status": "active",
    "untrusted_metadata": {
      "job_title": "Engineer",
      "preferred_locales": ["en", "es"]
    }
  },
  {
    "member_id": "member-test-83ei...",
    "organization_id": "organization-test-08264...",
    "email_address": "adalovelace@stytch.com",
    "email_address_verified": true,
    "name": "Miss Ada",
    "status": "active",
    "untrusted_metadata": {
      "timezone": "EST"
    }
  },
  {
    "member_id": "member-test-65yu...",
    "organization_id": "organization-test-02598...",
    "email_address": "adalovelace@stytch.com",
    "email_address_verified": true,
    "name": "Ada",
    "status": "active",
    "untrusted_metadata": {
      "display_theme": "dark"
    }
  }
]

Other considerations

Account deduplication

Stytch utilizes the email address as a unique primary key for identifying Members within an Organization. This means two things:

  1. Two different Members cannot use the same email address within a single Organization.
  2. Stytch will automatically consolidate Members who log into an Organization using the same email address with different auth methods. For example, an end user authenticates into Organization A using Email Magic Links and the email address example@stytch.com. Later, they authenticate into Organization A again with the same email address but this time using Google OAuth. Rather than create duplicate Member records, Stytch consolidates both auth instances under one Member object and member_id.

For this reason, you may need to merge your users' accounts before migrating to Stytch. If your script attempts to manually create two Members in an Organization in Stytch with the same email address, you will receive a duplicate_email error.

Passwords

Passwords are scoped to an individual Member object within a single Organization. This is unlike email-based auth methods, which can deduplicate and link multiple Members based on the email address. Passwords are unique and cannot be linked between Member objects, even if the Member objects share the same email address and are associated with the same end user.

This is designed to ensure strong multi-tenant separation and to mitigate unintended side-effects. For example, the admin of Org A should be allowed to reset the password of a Member in Org A, but should not be allowed to do so for a Member in Org B.

Linking Stytch Members and Organizations back to your db

You should continue to maintain your own internal user and groups tables in your application, and link Stytch’s member_ids and organization_ids in your schema. You can also add your internal identifier references as a trusted_metadata field on the Stytch Member and the Stytch Organization record using metadata.

What's next

With an understanding of how your user and organization data model will map to that of Stytch, see our guide to migrate users and organizations to Stytch.