New Ory Agent Security is now live! Claim your complimentary test drive. Get Started!

Skip to main content

Organizations for B2B Single Sign-On OIDC & SAML

Need help?

Ory Kratos uses organizations as a way to group users within one project. An organization always belongs to one Ory project. Within a project, an identity can belong to an organization or remain without an organization. Organizations contain multiple OIDC or SAML SSO connections. All members of an organization must use one of the organization's OIDC or SAML SSO connections to log in.

An organization can have multiple domains. Registrations for email addresses with a domain that belongs to an organization must go through one of the organization's OIDC or SAML SSO connections.

Some identity providers do not validate email domain ownership. This can lead to situations where Organization login is configured for a specified domain such as @example.com, but due to this lack of this email domain ownership validation by the identity provider, a users with other email domains such as @gmail.com can still authenticate successfully via the identity provider.

This will end up with the user being part of the configured organization in your Ory project, even if the domain does not match any of the configured domains.

Organizations require identifier-first authentication and two-step registration when using Account Experience 2.x or Ory Elements 1.x.

Manage organizations​

To create, update, or delete organizations via the Ory Console, go to

Organizations → All organizations in the Ory Console.

Create SSO connections for an organization​

After creating an organization, continue by adding one or more SSO OIDC connections.

Go to Organizations → All organizations in the Ory Console and continue by configuring the selected organization.

Pre-provisioning identities in an organization​

After creating an organization, you can pre-provision identities in it. This is useful when you need to create related data in your system but need the identity to be created in Ory Network first, before the user logs in for the first time.

To achieve this, set the organization_id property to the ID of the created organization in the identity, either when creating the identity, or by updating the identity's data using the Ory APIs.

To automate provisioning from an external identity provider instead, configure a SCIM client for the organization. The SCIM server creates and updates identities in the organization automatically. Because an identity can belong to only one organization, provisioning a user that already exists in a different organization fails with a conflict — see How SCIM relates to organizations for the full behavior and how to resolve it.

Bind an identity to an organization through the settings flow​

A signed-in user can join an organization by linking one of its SSO connections through the settings flow. When the user completes the link, Ory sets the identity's organization_id to that organization. There is no need to sign the user out or to pre-provision the identity.

To scope a settings flow to an organization, pass the organization ID in the organization query parameter when you initialize the flow:

https://$PROJECT_SLUG.projects.oryapis.com/self-service/settings/browser?organization=$ORGANIZATION_ID

The same parameter works for the API (native) flow at /self-service/settings/api.

Ory only honors the organization query parameter when one of the identity's email addresses is under the organization's configured domains. This prevents any signed-in user from scoping a flow to an arbitrary organization and enumerating its SSO connections. When no email address matches, the flow silently falls back to a regular, unscoped settings flow.

The check uses the identity's email verifiable addresses. An identity whose schema has no verification.via: email annotation has no email verifiable address and therefore cannot use the organization query parameter. This domain check does not apply when the identity is already bound to an organization — see below.

An organization-scoped settings flow behaves differently from a regular settings flow:

  • The settings flow returns link nodes only for the organization's OIDC and SAML connections. Other settings methods, such as password or social sign-in, are not part of the flow.
  • Connections the identity has already linked render as disabled. The organization owns the binding, so the user cannot remove it.
  • Submitting a link starts authentication with the organization's identity provider. On the callback, Ory links the credential and sets the identity's organization_id.
  • Unlink submissions are rejected. To remove a member from an organization, use the identity admin API.

When the signed-in identity is already bound to an organization, that organization takes precedence over the organization query parameter. An identity cannot be silently re-bound to a different organization through the settings flow.

If the identity's organization_id points to an organization that was deleted, the settings flow falls back to a non-organization scoped flow. This keeps account recovery and self-service settings working for users who were offboarded from a deleted organization.

Multi-factor authentication for organization members​

Organization members can complete second factors such as TOTP or WebAuthn to reach the aal2 authenticator assurance level. Before a second factor completes, Ory verifies that the session was authenticated through an OIDC or SAML SSO connection that is currently configured for the member's organization. A session without that proof — for example one whose SSO connection was removed or moved to a different organization since sign-in — cannot complete a second factor. The user must sign in through the organization's SSO connection again first.

Organization ID in OAuth2 and OpenID Connect tokens​

When an organization member signs in through an Ory OAuth2 / OpenID Connect flow using the hosted consent screen (Account Experience), the issued tokens carry the identity's organization ID:

  • organization_id in the ID token claims.
  • organization_id in the access token session data, surfaced under ext in JWT access tokens and promotable to a top-level claim.

Identities that don't belong to an organization get no such claim. For configuration details and behavior, see Organization ID claim.

SAML​

SAML (Security Assertion Markup Language) is an XML-based open standard used for exchanging authentication and authorization data between parties. The SAML integration in Ory Network uses the B2B Organization feature.

SAML via Ory Network​

This guide will walk you through the steps required to set up SAML Single Sign-On (SSO) with Ory Network.

Prerequisites​

Before proceeding, ensure you are on a plan that supports SAML SSO. SAML is available exclusively on select Enterprise plans. Contact us if you need SAML support.

  1. Go to Organizations → All organizations in the Ory Console to create an organization.
  2. Select "Add a new Enterprise SAML SSO connection" and follow the instructions to configure the SAML connection. Fill out the following form fields:
  • Label: A descriptive name for the SAML connection. This will be displayed to users.
  • Data mapping: A mapping from the SAML attributes to Ory's identity schema.
  • Raw IDP metadata XML: The XML metadata file from your SAML Identity Provider (IdP).
  1. After saving, copy the ACS URL and SP metadata URL shown in the provider details dialog. Use these values when configuring the SAML application in your Identity Provider.
  2. Navigate to your login screen to test the SAML connection.

Besides the ACS URL, configure the SAML application in your SAML Identity Provider with the service provider (SP) entity ID, also called audience URI. On the default engine (Polis), every provider of an organization uses the same SP entity ID, with or without per-provider ACS URLs:

  • Default: https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml/organizations/$ORGANIZATION_ID
  • Custom audience base URL (audience_override_base_url): https://$CUSTOM_DOMAIN/self-service/methods/saml/organizations/$ORGANIZATION_ID

Shared and per-provider ACS URLs​

On the default engine (Polis), the providers of a project share one ACS URL unless the project enables per-provider ACS URLs. With the shared ACS URL, Ory selects the connection by the entity ID of the IdP that sent the SAML response, so every provider in the project needs an IdP with a different entity ID.

Enable per-provider ACS URLs when several providers use the same IdP entity ID (for example Google Workspace, where one IdP serves several SAML applications). Each new provider then gets its own route, /saml/api/oauth/saml/$PROVIDER_ID, and the route selects the connection. Without a proxy ACS URL, the route is also the provider's ACS URL.

To enable per-provider ACS URLs, go to Project settings → Advanced in the Ory Console and turn on Per-provider SAML ACS URLs. The setting is stored as the polis.per_provider_acs_url feature flag of the project and is disabled by default.

The setting applies when a provider is created. A provider keeps the ACS URL it was created with, so you can change the setting without updating the IdP application of an existing provider:

  • A provider created while the setting is disabled stays on the shared ACS URL after you enable it.
  • A provider created while the setting is enabled keeps its own ACS URL after you disable it. The provider's acs_url field holds that URL.

If you show the ACS URL in your own SSO setup flow before the provider exists, derive it from the provider and the setting. If the provider has a proxy ACS URL, the ACS URL is that URL, exactly as written. Otherwise, use the shared ACS URL when polis.per_provider_acs_url is false, and the shared ACS URL followed by /$PROVIDER_ID when it is true.

Redirecting from a proxy ACS URL​

With a proxy ACS URL (proxy_acs_url), the IdP posts SAML responses to a URL on a host you operate, and your proxy sends the browser on to Ory. Redirect with HTTP status 307 or 308, so that the browser repeats the POST request with the SAML response. With 302 or 303, the browser follows the redirect with a GET request and drops the SAML response. Redirect the browser; don't pass the request on to Ory from your server.

Redirect a response to the route of its provider:

  • https://$HOST/saml/api/oauth/saml/$PROVIDER_ID when the provider is on its own route.
  • https://$HOST/saml/api/oauth/saml otherwise.

$HOST is any host that routes to the project: its custom domain or $PROJECT_SLUG.projects.oryapis.com.

A provider is on its own route when it was created while Per-provider SAML ACS URLs was on, with a provider ID of 4 to 64 characters from A-Z, a-z, 0-9, ., ~, _ and -. Such a provider has an acs_url. The identity configuration (GET https://api.console.ory.com/projects/$PROJECT_ID) shows it in services.identity.config.selfservice.methods.saml.config.providers, and GET https://api.console.ory.com/normalized/projects/$PROJECT_ID returns it in current_revision.kratos_selfservice_methods_saml_config_providers. Ory sets acs_url, and a save doesn't change it, whatever value the save sends. The Console shows an ACS URL for every provider, so it doesn't tell the routes apart.

A response to a login that Ory started has a RelayState that starts with boxyhq_jackson_. A response to an IdP-initiated login has no RelayState, or one that your IdP sets. You can always redirect a response to a login Ory started to the shared route, whatever URL it arrived at, because Ory finds the provider from the login session. That's the only option for a proxy ACS URL that several providers share. An IdP-initiated response for a provider on its own route fails on the shared route.

A new provider on its own route takes its proxy ACS URL, exactly as written, as its ACS URL. The ACS URL is fixed when the connection is created: changing proxy_acs_url later doesn't change it. On the shared route, a changed proxy_acs_url takes effect when you save it.

Every new or changed proxy ACS URL must meet these rules:

  • It's an absolute URL with the http or https scheme.
  • Its host is an IP address or a domain name. Write an IPv6 address in brackets, in its shortest form (RFC 5952, such as [2001:db8::1]), without a zone, and not as an IPv4-mapped address. A domain name consists of non-empty labels of ASCII letters, digits, -, and _, separated by dots, without a trailing dot, and its last label doesn't start with a digit. Write an internationalized domain name in punycode (xn--…).
  • If it has a port, the port is from 1 to 65535.
  • Its scheme and host are lowercase, and a port has no leading zeros and isn't the scheme's default (443 for https, 80 for http).
  • It has no user name or password.
  • It has no whitespace, control characters, or backslashes.
  • It's at most 2048 characters long.
  • Its path has no . or .. segments, including percent-encoded ones.

A save that breaks a rule fails with 400 Bad Request and changes nothing. The rules apply to every project. An empty value isn't checked; a new provider on its own route treats it as no proxy ACS URL. An unchanged value isn't checked again. When you create a project from a configuration, the rules apply to every proxy ACS URL and acs_url in it. When you create an onboarding portal link, its proxy ACS URL must meet the same rules.

A configuration that you create a project from, or copy to another project, adds the providers the project doesn't have yet as new providers. If one of them has additional ACS URLs, that project needs Per-provider SAML ACS URLs (the polis.per_provider_acs_url feature flag) turned on, or the save fails with 400 Bad Request.

Additional ACS URLs​

A provider on its own route can accept SAML responses addressed to further URLs besides its ACS URL. Use this when your proxy receives the responses of one provider at several URLs. For example, a provider with the proxy ACS URL https://auth.example.com/login?method=sso can also accept the IdP-initiated responses that its IdP sends to https://auth.example.com/sso/$ORGANIZATION_ID. List up to 10 such URLs in additional_acs_urls. Change the provider index (0 in the example below) to match the provider's position in the providers array.

curl -X PATCH --location "https://api.console.ory.com/projects/$PROJECT_ID/revision/$REVISION_ID" \
-H "Authorization: Bearer $WORKSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"op": "add",
"path": "/services/identity/config/selfservice/methods/saml/config/providers/0/additional_acs_urls",
"value": ["https://auth.example.com/sso/$ORGANIZATION_ID"]
}
]' \
| jq ".project.services.identity.config.selfservice.methods.saml"
  • The list applies only to a provider on its own route. Saving a new or changed list for a provider on the shared route fails with 400 Bad Request, and so does saving a provider on the native engine with a non-empty list.
  • Ory compares the response's Recipient with each URL exactly as written, so the case of the path and a trailing slash must match what the IdP sends. Every new URL in the list must meet the rules for proxy ACS URLs above, so its scheme and host are lowercase and it has no default port.
  • Your proxy redirects the responses it receives at these URLs to the provider's route, as it does for the proxy ACS URL.
  • When you update the provider, leaving out additional_acs_urls, or sending null, keeps the list, and an empty list ([]) removes it. A JSON Patch remove of additional_acs_urls removes the list, like [].
  • Switching the provider to the native engine removes its list. The Console doesn't show the list, and editing the provider there keeps it.
  • The SP metadata and the authentication requests of the provider name only its ACS URL (acs_url). Add the additional URLs to the IdP application yourself, for example as further reply URLs.

SP entity ID​

The SP entity ID identifies Ory as the SAML service provider. The IdP sends it as the audience of every SAML response, so the IdP application must be configured with it. Each provider stores its SP entity ID in sp_entity_id. The Console shows it in the provider details dialog, the identity configuration shows it in services.identity.config.selfservice.methods.saml.config.providers, and GET https://api.console.ory.com/normalized/projects/$PROJECT_ID returns it in current_revision.kratos_selfservice_methods_saml_config_providers. A configuration that you copy to another project carries sp_entity_id, so its providers keep this SP entity ID there. Leave out sp_entity_id to give them the default of that project.

A new provider gets a default when it's first saved:

  • Default engine (Polis): https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml, followed by /organizations/$ORGANIZATION_ID for a provider of an organization. A custom audience base URL (audience_override_base_url) takes the place of https://$PROJECT_SLUG.projects.oryapis.com, and a proxy SAML audience (proxy_saml_audience_override) takes the place of the whole value.
  • Native engine: https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml/metadata.

To use another value, set sp_entity_id. Change the provider index (0 in the example below) to match the provider's position in the providers array.

curl -X PATCH --location "https://api.console.ory.com/projects/$PROJECT_ID/revision/$REVISION_ID" \
-H "Authorization: Bearer $WORKSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"op": "add",
"path": "/services/identity/config/selfservice/methods/saml/config/providers/0/sp_entity_id",
"value": "https://auth.example.com/saml"
}
]'
  • A save that leaves out sp_entity_id, or sends null, keeps the stored value. That includes a save that switches the provider to the other engine, moves it to another organization, changes audience_override_base_url, or removes proxy_saml_audience_override. To change the value, set sp_entity_id.
  • A JSON Patch remove of sp_entity_id, in the identity configuration or on the normalized project revision, keeps the stored value, because Ory fills it.
  • A new or changed proxy_saml_audience_override on the default engine also sets sp_entity_id, unless the same save changes sp_entity_id itself.
  • A new or changed value must be at most 1024 characters long and must not contain whitespace or control characters. It doesn't have to be a URL. A save that breaks a rule fails with 400 Bad Request and changes nothing. An unchanged value isn't checked again.
  • Providers on the shared ACS URL whose IdPs have the same entity ID share one SAML connection, so they must have the same sp_entity_id. A save that adds such a provider with another value, or changes the value of one of them, fails with 400 Bad Request and names the providers.
  • A provider that doesn't store an SP entity ID yet has no sp_entity_id field. Its SP entity ID is the default above, computed from its current settings, and the next save of the project stores it.

Native SAML engine​

Providers that set engine to native are processed by Ory directly instead of by Polis. This engine is in preview and must be enabled for the project first. Its SAML endpoints are derived from the project's canonical URL, https://$PROJECT_SLUG.projects.oryapis.com, and the provider ID. They don't use your custom domain, and proxy_acs_url does not apply. Configure the IdP with these URLs; custom-domain URLs don't match the ACS URL and SP entity ID that native SAML checks responses against.

  • ACS URL: https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml/acs/$PROVIDER_ID
  • SP entity ID: the provider's sp_entity_id. For a new provider, it's https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml/metadata.
  • SP metadata: https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/saml/metadata/$PROVIDER_ID

The SP metadata document carries the ACS URL, the entity ID, and the signing certificate, so the simplest way to configure the IdP is to import it. The Console shows all three values in the provider details dialog.

Switching a provider between the default engine and the native engine changes its ACS URL and SP metadata, so the IdP application has to be updated with the new values before users can sign in again. The provider keeps its SP entity ID. A provider on its own route also keeps its acs_url and uses it again when you switch it back to the default engine. The native engine doesn't use it, so the identity configuration doesn't show it while the provider is on the native engine. Switching a provider to the native engine also removes its additional ACS URLs. With the API, remove additional_acs_urls or set it to [] in the same update; a native provider with a list fails with 400 Bad Request.

The native engine sends authentication requests with the HTTP-Redirect binding when the IdP metadata lists it, and with HTTP-POST otherwise, like the default engine. To use a specific binding, set Binding in the provider's advanced settings.

The native engine trusts the signing certificates in the IdP metadata for their keys only and doesn't check their validity dates, so an IdP that keeps signing with an expired certificate still works. To stop trusting a certificate, remove it from the IdP metadata. Every SAML response must carry a NameID with a value, because the native engine identifies the user by it.

The native engine accepts responses signed with RSA-SHA256, ECDSA-SHA256, or RSA-SHA1, and assertions and NameIDs encrypted with AES-GCM and RSA-OAEP key transport. It rejects AES-CBC encryption, so configure the IdP to use AES-GCM. Builds with the FIPS 140-3 module enabled don't accept RSA-SHA1 by default.

By default, every project update writes the SAML connections of all providers of the project. To write only the connections of the providers an update changes, go to Project settings → Advanced in the Ory Console and turn on Write only changed SAML connections. The setting is stored as the polis.saml_delta_sync feature flag of the project and is disabled by default.

With the setting turned on, a single project update, whether made in the Ory Console or with PUT or PATCH on the project, can add, change, or remove at most 25 SAML providers in total. An update over the limit is rejected with a 400 Bad Request error and changes nothing. To change more providers, split the change across several updates.

Data mapping​

You can configure the mapping of SAML attributes to Ory's identity schema using Jsonnet. All custom SAML attributes defined at the Identity Provider (IdP) will be available in the raw_claims object within claims. These attributes can then be mapped to the Ory identity schema.

warning

Ensure that the appropriate identity schema is created before mapping attributes. The email attribute is natively available in claims.email, everything else is nested under claims.raw_claims.

Example SAML data mapping​

This mapper sets only the email trait. It works with the preset email identity schema:

local claims = std.extVar('claims');

{
identity: {
traits: {
email: claims.email,
},
},
}

To also map firstName and lastName from the SAML Identity Provider, your identity schema must define firstName and lastName traits. If it doesn't, Ory rejects the mapped traits with a validation error such as additionalProperties "firstName", "lastName" not allowed and shows the user a registration form instead of signing them in. The mapper sets each trait only when the IdP sends the attribute:

local claims = std.extVar('claims');
local rawClaims = std.get(claims, 'raw_claims', {});

{
identity: {
traits: {
email: claims.email,
[if std.objectHas(rawClaims, 'firstName') then 'firstName' else null]: rawClaims.firstName,
[if std.objectHas(rawClaims, 'lastName') then 'lastName' else null]: rawClaims.lastName,
},
},
}
Data mapping on the native engine​

The data mapper of a provider on the native SAML engine can read three variables:

  • std.extVar('saml') holds the SAML assertion as Ory validated it. Use it for new mappers on the native engine.
  • std.extVar('claims') holds the same assertion in the shape the default engine passes. A mapper written for the default engine works unchanged unless it reads a claim that only the default engine sets. These claims are listed below.
  • std.extVar('identity') holds the traits and metadata of the identity. See Access the current identity in the mapper.

The saml variable has these fields:

FieldValue
subjectThe value of the assertion's NameID. Ory identifies the user of the connection by this value.
subject_formatThe format of the NameID, for example urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress.
issuerThe entity ID of the IdP.
session_indexThe SessionIndex of the assertion's authentication statement.
attributesMaps each attribute Name to an array of its untrimmed values. Attributes of the same Name are combined.

The following mapper uses the NameID as the email address, so it requires an IdP that sends an email address as the NameID. If your IdP sends an opaque identifier, read the email address from an attribute instead.

local saml = std.extVar('saml');
local attribute(name) = if std.objectHas(saml.attributes, name) then saml.attributes[name][0] else null;

{
identity: {
traits: {
email: saml.subject,
[if attribute('firstName') != null then 'firstName']: attribute('firstName'),
},
},
}

On the native engine, claims and claims.raw_claims don't contain iss, aud, exp, iat, nonce, requested, polis_login_id, and idHash. claims.sub is the value of an attribute named id, otherwise the NameID, otherwise the SHA-256 hash of the email address, as on the default engine. It can therefore differ from saml.subject.

The native engine reads the same mapper output as the default engine: identity.traits, identity.metadata_public, identity.metadata_admin, identity.verified_addresses, and identity.region.

Update identity on login​

By default, Ory runs the data mapper only the first time a user signs in through a SAML connection. To keep identity data in sync with the SAML identity provider (IdP), set update_identity_on_login to automatic on the connection. With this setting, Ory re-runs the connection's Jsonnet data mapper on every SAML login and updates the identity's traits and metadata whenever they change.

Use automatic when the SAML IdP is the source of truth for attributes that change over time, such as group memberships, roles, or profile information.

The default is never. Existing SAML connections keep their current behavior until you opt in.

  1. Go to Organizations → All organizations in the Ory Console and open the organization that holds the SAML connection.
  2. Edit the Enterprise SAML SSO connection.
  3. Set Update identity on login to automatic.
Access the current identity in the mapper​

When you set update_identity_on_login to automatic, Ory passes the current identity to the data mapper as an additional variable std.extVar('identity'). Use it to write conditional logic — for example, to preserve trait values a user has already set, or to merge SAML IdP data selectively. The identity variable holds the identity's current traits, metadata_public, and metadata_admin. The example treats a missing or null value as an empty object. To use it, your identity schema must define the display_name and groups traits.

local claims = std.extVar('claims');
local identity = std.extVar('identity');
local orEmpty(value) = if value == null then {} else value;
local rawClaims = orEmpty(std.get(claims, 'raw_claims'));
local traits = orEmpty(std.get(identity, 'traits'));

// Keep the display name if the user has set one, otherwise use the value from the IdP (if any).
local displayName = std.get(traits, 'display_name', std.get(rawClaims, 'displayName', ''));

{
identity: {
traits: {
email: claims.email,
[if displayName != '' then 'display_name' else null]: displayName,
// Always update groups from the IdP.
[if std.objectHas(rawClaims, 'groups') then 'groups' else null]: rawClaims.groups,
},
},
}

Ory also passes the existing identity to the mapper during account linking. This happens when a user signs in through an SSO connection for the first time and both of the following are true:

  • The mapper output doesn't satisfy the identity schema, for example because the identity provider doesn't send a required trait.
  • The sign-in conflicts with an existing identity, for example because the email address is already registered.

Ory then evaluates the mapper a second time with std.extVar('identity') set to the existing identity. If the result satisfies the identity schema, the user goes straight to the sign-in screen that confirms the link with an existing credential, and isn't asked for the missing traits. Otherwise, Ory asks the user for the missing traits as before.

A mapper opts in by falling back to the existing traits:

local claims = std.extVar('claims');
local identity = std.extVar('identity');

{
identity: {
traits: {
email: claims.email,
// The identity provider doesn't send a name. Reuse the name of the existing identity when linking.
[if "name" in identity.traits then "name" else null]: identity.traits.name,
},
},
}

Linking only adds the SSO credential to the existing identity. It doesn't change the identity's traits, and Ory never shows the existing identity's traits to the user before they confirm the link. A mapper that doesn't read std.extVar('identity') behaves as before.

Behavior details​
  • Metadata preservation. When the mapper omits metadata_public or metadata_admin from its output, Ory preserves the existing values. When the mapper explicitly outputs {}, the field is cleared.
  • Schema validation. Before Ory persists the identity, it validates the update against the identity schema. If the mapper produces invalid traits, Ory fails the login with a validation error.
  • No credential changes. This feature never modifies credentials. Addresses keep their verification state, and addresses the mapper lists in identity.verified_addresses are marked as verified.

Signing certificate expiry details​

The SAML connection includes a valid_to attribute, which is an array of expiry dates for the signing certificates associated with the connection.

Each date is returned in the same format as Node.js crypto.X509Certificate.validTo, matching OpenSSL’s textual representation:

MMM dd HH:mm:ss yyyy GMT

Example:

Jun 10 09:16:40 2038 GMT

You can use this information to externally monitor certificate expirations or integrate it into your internal workflows and alerting systems as needed.

Break-glass account recovery for SSO​

When an organization's SSO provider is unavailable, organization members can't sign in. Break-glass account recovery lets designated users bypass SSO enforcement and recover access through email-based recovery.

Each recovery address has a break_glass_for_organization field that stores the organization UUID it applies to. Recovery is only allowed when this field matches the identity's current organization. If the user moves to a different organization, the flag doesn't carry over.

For Ory Network users, the easiest way to manage this is through the Ory Console SSO settings.

Set break-glass via the identity admin API​

Set the break_glass_for_organization field on a recovery address to the organization's UUID:

curl -X PATCH "https://$PROJECT_SLUG.projects.oryapis.com/admin/identities/$IDENTITY_ID" \
-H "Authorization: Bearer $ORY_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"op": "replace",
"path": "/recovery_addresses/0/break_glass_for_organization",
"value": "<your-organization-id>"
}
]'

To disable break-glass recovery, set the value to the nil UUID:

curl -X PATCH "https://$PROJECT_SLUG.projects.oryapis.com/admin/identities/$IDENTITY_ID" \
-H "Authorization: Bearer $ORY_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"op": "replace",
"path": "/recovery_addresses/0/break_glass_for_organization",
"value": "00000000-0000-0000-0000-000000000000"
}
]'
warning

Grant break-glass recovery only to a small number of trusted users. Any user with this flag can bypass SSO and recover their account through email.

Self-service organization onboarding​

Need help?

The onboarding portal is a powerful tool designed to simplify complex identity and access management tasks for businesses and their partners.

Streamline organization onboarding​

The onboarding portal simplifies setting up and managing identity connections with external organizations.

The onboarding portal aims to:

  • Simplify complex integrations: A self-service or guided experience removes the need for client IT administrators to be SAML/SCIM experts.
  • Reduce onboarding time: External administrators configure connections directly through a user-friendly interface instead of lengthy manual setup and back-and-forth communication.
  • Enhance security and control: Shareable links don't expose sensitive information. Administrators configure their side securely while maintaining control over their IdP settings.
  • Enable self-service: SaaS providers can let customers manage their own SSO/SCIM connections, freeing up engineering and support teams.
  • Scale B2B integrations: Manual management becomes unsustainable as enterprise clients grow. The portal provides a scalable solution.
  • Validate instantly: Test SSO connections immediately to verify integration before deployment, reducing troubleshooting time.

The onboarding is relevant for SaaS providers serving B2B or B2B2C customers, enterprise IT administrators managing identity providers, and developers building multi-tenant applications.

Provider support:

  • The onboarding portal supports all well known providers. You can also connect any SAML/OIDC compliant provider using the Generic SAML/OIDC IdP option. If you don't find your provider listed, please contact Ory Support.

SCIM support​

The onboarding portal allows you to set up SCIM provisioning. For an organization, you can create, update, and remove SCIM servers. Guided walkthroughs are available for Microsoft Entra ID, Google Workspace, and Okta.

IdP-initiated login​

SAML connections support IdP-initiated login, where people start the login from their identity provider instead of from your application. Organization administrators turn it on for their connection in the onboarding portal, and project administrators can do the same in the Ory Console. It is off by default.

warning

IdP-initiated login is inherently open to login CSRF: anyone who can reach the assertion consumer service can start a login for an account they control and try to complete it in another person's browser. Turn it on only for connections whose identity provider requires it, and make sure your application does not treat the first authenticated session after an IdP-initiated login as proof of intent for a sensitive action.

Go to Organizations → All organizations in the Ory Console and continue by configuring the selected organization.

On the Edit Organization page, under the Onboarding Portal section, click Generate link. If your project has a custom domain configured, you must choose between the project slug and the custom domain as the link's base URL. You can then share this link with the organization administrators.

https://console.ory.com/projects/<id>/organizations/<id>/onboarding-portal

Onboarding portal link

Configure provider-specific data mappings​

You configure data mappers in the Onboarding Portal by attaching a Jsonnet script to each provider that supports mapping (for example, social sign-in providers, SAML, SCIM).

The mapper must return an object like:

local claims = std.extVar('claims'); // or std.extVar('scim') for SCIM

{
identity: {
traits: {
// map incoming data to your identity schema traits
[if 'email' in claims then 'email' else null]: claims.email,
},
},
}

For SAML organizations, SAML attributes are available under claims.email and claims.raw_claims. SAML mapping

For SCIM provisioning, the SCIM user object is available as std.extVar('scim') and you map it to the identity in the same way. SCIM mapping

For social sign-in, all upstream data is available as std.extVar('claims'), including standard claims and any raw_claims for non-standard fields. Social Sign-In mapping

https://console.ory.com/projects/<id>/organizations/<id>/onboarding-portal

Onboarding portal link

Expiry​

The link generated from the Ory Network Console expires in 7 days. The API allows you to set an expiration value with a minimum expiry of 1 day. Once the link expires, it no longer works. You can also delete the link and generate a new one.

Handover and using the portal​

Once you generate the link, share it with the organization's administrator. They can access this link multiple times until its expiration to manage SSO and SCIM connections.

https://<your-slug>.projects.oryapis.com/onboarding/<unique-token>

Onboarding portal

Manage SSO​
https://<your-slug>.projects.oryapis.com/onboarding/<unique-token>/sso

Onboarding portal

Manage SCIM​
https://<your-slug>.projects.oryapis.com/onboarding/<unique-token>/scim

Onboarding portal