Browse the docs
Guides

Enable SSO

Let an enterprise tenant sign in with their own identity provider over SAML or OIDC, route their users by email domain, and keep accounts in sync with SCIM.

Single sign-on connects an organisation to its own identity provider (IdP) such as Okta, Entra ID or Google Workspace. OrthID supports both SAML 2.0 and OIDC. A connection belongs to one organisation, so each tenant manages its own login while your application sees the same OrthID session and actor model throughout.

1. Create the connection

Create an SSO connection on the organisation and choose the protocol. For SAML you supply the IdP metadata URL (or upload the XML); for OIDC you supply the issuer, client ID and client secret. OrthID returns the ACS and entity values to hand back to the IdP admin.

scripts/create-sso.ts
import { orthid } from "@orthid/sdk";

// SAML connection for an organisation.
const connection = await orthid.sso.createConnection({
  organizationId: "org_clinic_42",
  protocol: "saml",
  name: "Okta (Acme Health)",
  saml: {
    metadataUrl: "https://acme.okta.com/app/exk1/sso/saml/metadata",
    // Map IdP claims onto the OrthID user.
    attributeMap: {
      email: "NameID",
      firstName: "FirstName",
      lastName: "LastName",
    },
  },
  // Domains whose users are routed to this connection.
  domains: ["acmehealth.com"],
});

// Hand these back to the IdP administrator.
console.log(connection.acsUrl);     // SAML assertion consumer service
console.log(connection.entityId);   // OrthID service provider entity ID

An OIDC connection follows the same shape with an issuer instead:

scripts/create-sso-oidc.ts
import { orthid } from "@orthid/sdk";

await orthid.sso.createConnection({
  organizationId: "org_clinic_42",
  protocol: "oidc",
  name: "Entra ID (Acme Health)",
  oidc: {
    issuer: "https://login.microsoftonline.com/<tenant-id>/v2.0",
    clientId: process.env.ACME_OIDC_CLIENT_ID,
    clientSecret: process.env.ACME_OIDC_CLIENT_SECRET,
    scopes: ["openid", "email", "profile"],
  },
  domains: ["acmehealth.com"],
});

2. Route users by domain

The domains on a connection drive domain-based routing. When a user enters an email whose domain matches a verified connection, the hosted <SignIn/>skips the password step and sends them straight to their IdP. A domain must be verified by the organisation before it routes traffic, which stops one tenant from claiming another tenant’s users.

scripts/verify-domain.ts
import { orthid } from "@orthid/sdk";

// Begin verification: returns a DNS TXT record to publish.
const { txtRecord } = await orthid.sso.startDomainVerification({
  organizationId: "org_clinic_42",
  domain: "acmehealth.com",
});
// txtRecord -> "orthid-verify=8c1f...": add it to the domain's DNS.

// Once the record is live, confirm it.
await orthid.sso.verifyDomain({
  organizationId: "org_clinic_42",
  domain: "acmehealth.com",
});
Verified domains only
Only verified domains route to a connection. Until the DNS record is confirmed, users at that domain keep their existing login. This is what makes domain-based routing safe in a multi-tenant deployment.

3. Provision with SCIM

SCIM keeps your tenant’s directory and OrthID in sync. When the IdP creates, updates or deactivates a user, OrthID mirrors the change, so a deprovisioned employee loses access without a manual step. Enable SCIM on the connection to get a base URL and a bearer token to paste into the IdP.

scripts/enable-scim.ts
import { orthid } from "@orthid/sdk";

const scim = await orthid.sso.enableScim({
  connectionId: connection.id,
});

// Configure these in the IdP's provisioning settings.
console.log(scim.baseUrl); // https://api.orthid.dev/scim/v2/<connection>
console.log(scim.token);   // bearer token, shown once
Store the SCIM token securely
The SCIM bearer token is shown only once and grants directory write access for the connection. Paste it straight into the IdP and rotate it if it is ever exposed.

Next steps

  • Invite members to add people who are not yet in the IdP, or to seed the first admins before SCIM takes over.
  • Add MFA as a second factor for users who sign in without an enterprise IdP.