Concepts

One user, many orgs

The single most important difference between Authio and WorkOS: a real B2B identity model that doesn't force duplicate accounts.

WorkOS scopes a user to a single organization. If your customer joins a second org on your platform, they have to use a second email. This is, frankly, terrible UX for any modern B2B product. Authio fixes it.

The model

At the schema level, the relationship looks like this:

Project
  └── Users               (project-scoped; canonical identity = (project, email))
  └── Organizations       (B2B accounts in your customer's product)
  └── Memberships         (the join: one User ↔ many Organizations)

A User has ID user_… and is keyed by (project_id, email). They never live inside an organization. Instead, a Membership row links them to each organization with an independent role and status:

memberships
  id              | mem_zXY…
  project_id      | proj_2eh…
  user_id         | user_alice
  organization_id | org_acme
  role            | admin
  status          | active
  joined_at       | 2026-05-13T13:42:53Z

memberships
  id              | mem_aBC…
  project_id      | proj_2eh…
  user_id         | user_alice          ← same user
  organization_id | org_globex          ← different org
  role            | member
  status          | active

Sessions are user-scoped, not org-scoped

After authentication (passkey, magic link, OAuth, SAML, anything), Authio mints a JWT with sub = user_id and an act_org claim that names the active organization. The same user can switch act_org in-session without re-authenticating, with a single API call:

POST /v1/sessions/switch-org
{
  "organization_id": "org_globex"
}

200 OK
{
  "access_token": "<new JWT with same sub, new act_org>",
  "active_organization": { "id": "org_globex", "name": "Globex Inc" },
  "memberships": [ ... all the user's orgs ... ]
}

Every membership change is captured in an audit event (session.org_switched) so customers’ security teams can see the pivot.

Privacy boundary

Important. Org admins can see members of their org. They can never enumerate other orgs that those members belong to. The Management API endpoints are deliberately constructed so cross-org queries are impossible from an org-admin’s vantage point. Only your project owner (the holder of an sk_live_ key) can list all of a user’s memberships.

SDK ergonomics

Drop-in components in @authio/react render the entire flow:

import {
  useUser,
  useOrganizations,
  useActiveOrganization,
  useSwitchOrganization,
  OrganizationSwitcher,
} from "@authio/react";

const { user } = useUser();
const { organizations } = useOrganizations();      // every org user belongs to
const { organization, role } = useActiveOrganization();
const switchOrg = useSwitchOrganization();

<OrganizationSwitcher createOrganizationUrl="/orgs/new" />

Where this matters

  • Vendors who sell to multiple teams in the same company.Stop emailing the same dev "use a different account when logging into the staging org."
  • Marketplaces and platforms. A consultant working across many client tenants is a single human being — their auth should reflect that.
  • Any product where users naturally span boundaries.Slack, Linear, GitHub, Figma, Notion all model this. Now your product can too without writing it from scratch.