Identity & Access
SAML SSO & SCIM Provisioning
Configure SAML single sign-on and SCIM user provisioning for Rhombus via the API — integrate Okta, Azure AD, Google Workspace, OneLogin, and other IdPs.
On this page
- Overview
- Architecture at a glance
- Before you begin
- Read current SAML settings
- Configure SAML
- The OrgSamlSettingsType fields
- Upload IdP metadata
- JIT vs SCIM
- Rotating IdP metadata
- Break-glass access
- Get the SCIM endpoint URLs
- Initial SCIM setup
- Setup options
- Read current SCIM settings
- Role format compatibility
- Update SCIM settings
- Rotate or revoke the SCIM bearer token
- IdP-specific setup notes
- Auditing SSO events
- Troubleshooting
- Next steps
Overview
Rhombus supports SAML 2.0 so your employees can sign in to the Rhombus Console with their existing corporate identity (Okta, Azure AD / Microsoft Entra, Google Workspace, OneLogin, and any SAML-compliant IdP), and SCIM 2.0 so user lifecycle changes in your IdP propagate to Rhombus automatically.
This guide covers the API surface for configuring both. Use it when you need to:
- Manage Rhombus as infrastructure-as-code (Terraform, Pulumi, in-house CI scripts)
- Rotate IdP signing certificates on a scheduled cadence
- Onboard many Rhombus orgs from a partner or MSP control plane
- Audit or diff identity configuration across environments
- Stand up a new tenant end-to-end without clicking through the Console
If you only need to configure SSO once for a single organization, the Rhombus Console has a UI for everything in this guide — but everything the UI can do is exposed via the API.
What this guide isn't. If you're a third-party developer building an application that authenticates Rhombus users (a "Sign in with Rhombus" flow), you want Sign in with Rhombus instead. That's OAuth 2.0 with Rhombus as the Identity Provider — a completely separate surface from the workforce-SSO configuration covered here.
Architecture at a glance
Two independent flows share your IdP but don't otherwise depend on each other:
- SAML SSO authenticates users at sign-in time. Your IdP posts a SAML assertion to Rhombus; Rhombus validates it against the IdP metadata XML you uploaded.
- SCIM propagates user lifecycle events (create, update, deactivate) from your IdP to Rhombus continuously, without requiring users to sign in first.
You can run either one alone, but most deployments run both: SAML for sign-in, SCIM for provisioning.
Before you begin
Before you start, make sure you have:
- A Rhombus API key with organization-admin permissions (generated in the Rhombus Console under Settings → Integrations & Developer Resources → API Tokens)
- An identity provider that supports SAML 2.0 and (for provisioning) SCIM 2.0
- The IdP metadata XML for your SAML application, either as a file or URL
- A recovery user account with a password that bypasses SAML — see break-glass access before you enable SSO
Part 1: SAML SSO
Two endpoints cover the entire SAML configuration lifecycle:
| Endpoint | Purpose |
|---|---|
POST | Read current SAML settings for the organization |
POST | Replace SAML settings |
getSAMLSettings (v1, no V2 suffix) and updateSAMLSettings (v1) are deprecated. Use the V2 endpoints shown in this guide.
Read current SAML settings
Fetch the current configuration so you can diff against what you intend to push, or confirm a previous update landed.
import requests
headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
}
response = requests.post(
"https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
headers=headers,
json={},
)
for setting in response.json().get("samlSettings", []):
print(f"team={setting.get('teamName')} enabled={setting.get('enabled')} "
f"jit={setting.get('justInTimeAccountProvisioningEnabled')}")const response = await fetch(
"https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
{
method: "POST",
headers: {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
}
);
const { samlSettings = [] } = await response.json();
for (const s of samlSettings) {
console.log(`team=${s.teamName} enabled=${s.enabled} jit=${s.justInTimeAccountProvisioningEnabled}`);
}req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
strings.NewReader("{}"))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result struct {
SamlSettings []struct {
TeamName string `json:"teamName"`
Enabled bool `json:"enabled"`
JustInTimeAccountProvisioningEnabled bool `json:"justInTimeAccountProvisioningEnabled"`
} `json:"samlSettings"`
}
json.NewDecoder(resp.Body).Decode(&result)The response contains a samlSettings array. Most orgs have one entry — a second entry exists only for deployments that span both rhombus.com and rhombussystems.com domains.
Configure SAML
POST /api/org/updateSAMLSettingsV2 replaces the organization's SAML configuration. Include the entries you want to exist after the call — fields omitted inside an entry revert to defaults.
The OrgSamlSettingsType fields
| Field | Type | Description |
|---|---|---|
enabled | boolean | Turn SAML sign-in on or off. Set to false to disable SSO without losing your metadata. |
idpMetaDataXml | string | The raw SAML metadata XML from your IdP (entity descriptor, signing cert, SSO URLs). |
justInTimeAccountProvisioningEnabled | boolean | If true, a Rhombus user is auto-created the first time someone signs in via SAML. See JIT vs SCIM below. |
enabledForRhombusKey | boolean | Also require SAML for the Rhombus Key mobile access app. |
addUsersOnRoleMismatch | boolean | If true, sign-in succeeds even when the IdP-asserted role doesn't match a Rhombus role; the user is added with a default role. |
teamName | string | Display label used in the Console. |
domain | enum | RHOMBUS_COM or RHOMBUS_SYSTEMS_COM. Most customers use RHOMBUS_COM. |
rhombusKeyAppSettings | object | Per-app toggles for the Rhombus Key mobile app (remote unlock, SAML bypass for mobile, etc.). |
Upload IdP metadata
import requests
# Read your IdP's federation metadata XML
with open("idp-metadata.xml", "r") as f:
idp_metadata_xml = f.read()
headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
}
body = {
"samlSettings": [
{
"enabled": True,
"idpMetaDataXml": idp_metadata_xml,
"justInTimeAccountProvisioningEnabled": True,
"enabledForRhombusKey": True,
"addUsersOnRoleMismatch": False,
"teamName": "Acme Corp",
"domain": "RHOMBUS_COM",
}
]
}
response = requests.post(
"https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
headers=headers,
json=body,
)
response.raise_for_status()
print("SAML configuration updated.")import fs from "node:fs/promises";
const idpMetadataXml = await fs.readFile("idp-metadata.xml", "utf8");
const response = await fetch(
"https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
{
method: "POST",
headers: {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
samlSettings: [
{
enabled: true,
idpMetaDataXml: idpMetadataXml,
justInTimeAccountProvisioningEnabled: true,
enabledForRhombusKey: true,
addUsersOnRoleMismatch: false,
teamName: "Acme Corp",
domain: "RHOMBUS_COM",
},
],
}),
}
);
if (!response.ok) throw new Error(`Update failed: ${await response.text()}`);
console.log("SAML configuration updated.");xmlBytes, _ := os.ReadFile("idp-metadata.xml")
body, _ := json.Marshal(map[string]any{
"samlSettings": []map[string]any{
{
"enabled": true,
"idpMetaDataXml": string(xmlBytes),
"justInTimeAccountProvisioningEnabled": true,
"enabledForRhombusKey": true,
"addUsersOnRoleMismatch": false,
"teamName": "Acme Corp",
"domain": "RHOMBUS_COM",
},
},
})
req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
bytes.NewReader(body))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil || resp.StatusCode != 200 {
// handle error
}updateSAMLSettingsV2 is a replacement operation. To change one field (say, teamName), read the current settings first, modify the entry you want, and send the full array back. Omitting an entry that previously existed removes it.
JIT vs SCIM
You have two options for getting users into Rhombus:
| Option | What it does | When to choose it |
|---|---|---|
JIT (justInTimeAccountProvisioningEnabled: ) | A Rhombus user record is created the first time a person signs in via SAML. | Small teams, low churn, SCIM unavailable on your IdP tier. |
| SCIM (Part 2) | Your IdP pushes create, update, and deactivate events to Rhombus as they happen. | Larger orgs, compliance-driven deprovisioning requirements, role changes that must propagate immediately. |
You can enable both — JIT handles any user who signs in before SCIM syncs them, and SCIM keeps the directory consistent thereafter. Most production deployments run both.
Rotating IdP metadata
IdP signing certificates rotate. Build a scheduled job that pulls fresh metadata from your IdP and pushes it to Rhombus — Rhombus keeps accepting assertions signed with the old cert until you replace the metadata.
import requests
def rotate_saml_metadata(api_key: str, new_metadata_xml: str) -> None:
"""Fetch current SAML settings, swap in new IdP metadata, push back."""
headers = {
"x-auth-scheme": "api-token",
"x-auth-apikey": api_key,
"Content-Type": "application/json",
}
# 1. Read current settings
current = requests.post(
"https://api2.rhombussystems.com/api/org/getSAMLSettingsV2",
headers=headers,
json={},
).json()
settings = current.get("samlSettings") or []
if not settings:
raise RuntimeError("No existing SAML settings to rotate.")
# 2. Replace the metadata XML on each entry; leave other fields untouched
for entry in settings:
entry["idpMetaDataXml"] = new_metadata_xml
# 3. Push back
response = requests.post(
"https://api2.rhombussystems.com/api/org/updateSAMLSettingsV2",
headers=headers,
json={"samlSettings": settings},
)
response.raise_for_status()Schedule the rotation well before your IdP cert actually expires. Verify a real sign-in immediately after rotation, before closing the maintenance window — a malformed XML update can prevent logins until you revert.
Break-glass access
Before you enable SAML, make sure at least one admin user has a Rhombus-native password and can bypass SAML. Otherwise a misconfiguration locks everyone out and the only recovery path is Rhombus Support.
Every Rhombus user record has a bypassSaml boolean. Keep one or two admin accounts with bypassSaml: true as a recovery path. These accounts should:
- Use strong, unique passwords stored in your secrets manager
- Have MFA enabled
- Be audited regularly — treat them like root credentials
Never disable SAML and remove all break-glass accounts in the same change. Test your recovery path at least once per quarter.
Part 2: SCIM provisioning
SCIM (System for Cross-domain Identity Management) lets your IdP push user lifecycle events directly to Rhombus — no sign-in required.
Five endpoints cover SCIM end-to-end:
| Endpoint | Purpose |
|---|---|
POST | Get the SCIM endpoint URLs to hand to your IdP |
POST | First-time SCIM setup; returns a bearer token |
POST | Read current SCIM configuration |
POST | Change SCIM options (welcome emails, role behavior, etc.) |
POST | Invalidate the current SCIM bearer token |
Get the SCIM endpoint URLs
Your IdP needs two pieces of information to connect: the endpoint URL and a bearer token. The endpoint URL comes from getScimDisplayInfo:
import requests
response = requests.post(
"https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
headers={
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={},
)
info = response.json()
print("Standard SCIM endpoint:", info["scimEndpointUrl"])
print("Azure AD SCIM endpoint:", info["azureScimEndpointUrl"])const response = await fetch(
"https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
{
method: "POST",
headers: {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
}
);
const info = await response.json();
console.log("Standard SCIM endpoint:", info.scimEndpointUrl);
console.log("Azure AD SCIM endpoint:", info.azureScimEndpointUrl);req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/getScimDisplayInfo",
strings.NewReader("{}"))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var info struct {
ScimEndpointUrl string `json:"scimEndpointUrl"`
AzureScimEndpointUrl string `json:"azureScimEndpointUrl"`
}
json.NewDecoder(resp.Body).Decode(&info)Most IdPs use scimEndpointUrl. Azure AD / Entra requires the Azure-specific variant due to Microsoft-specific schema quirks.
Initial SCIM setup
The first call provisions a bearer token. This token is shown once and cannot be retrieved later — capture it immediately into your secrets manager.
import requests
response = requests.post(
"https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
headers={
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"sendWelcomeEmailToNewUsers": True,
"sendWelcomeEmailToNewRhombusKeyUsers": True,
"addUsersOnRoleMismatch": False,
},
)
data = response.json()
if data.get("scimAccessAlreadySetupFailure"):
raise RuntimeError("SCIM is already set up — revoke first or use update.")
scim_bearer_token = data["token"]
# Store scim_bearer_token in your secrets manager immediately.
# Paste it into your IdP's SCIM provisioning settings as the bearer token.const response = await fetch(
"https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
{
method: "POST",
headers: {
"x-auth-scheme": "api-token",
"x-auth-apikey": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
sendWelcomeEmailToNewUsers: true,
sendWelcomeEmailToNewRhombusKeyUsers: true,
addUsersOnRoleMismatch: false,
}),
}
);
const data = await response.json();
if (data.scimAccessAlreadySetupFailure) {
throw new Error("SCIM is already set up — revoke first or use update.");
}
const scimBearerToken = data.token;
// Store scimBearerToken in your secrets manager immediately.body, _ := json.Marshal(map[string]any{
"sendWelcomeEmailToNewUsers": true,
"sendWelcomeEmailToNewRhombusKeyUsers": true,
"addUsersOnRoleMismatch": false,
})
req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
bytes.NewReader(body))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var data struct {
Token string `json:"token"`
ScimAccessAlreadySetupFailure bool `json:"scimAccessAlreadySetupFailure"`
}
json.NewDecoder(resp.Body).Decode(&data)
// Store data.Token in your secrets manager immediately.The SCIM bearer token is shown once. Losing it means revoking the current access and setting up again — and your IdP loses sync until its token is updated.
Setup options
| Field | Type | Description |
|---|---|---|
sendWelcomeEmailToNewUsers | boolean | Email new users when SCIM creates their Rhombus account. |
sendWelcomeEmailToNewRhombusKeyUsers | boolean | Same, but for users added to the Rhombus Key mobile access app. |
addUsersOnRoleMismatch | boolean | Create the user anyway if the IdP-asserted role doesn't map cleanly. |
rhombusKeyAppSettings | object | Per-app toggles for Rhombus Key provisioning. |
Read current SCIM settings
findSCIMSettingsForOrg returns the full SCIMSettingsType record, including the role format setting, which matters for IdP compatibility:
response = requests.post(
"https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
headers=headers,
json={},
)
settings = response.json().get("scimSettings", {})
print("rolesFormat:", settings.get("rolesFormat")) # LIST_OF_STRINGS or LIST_OF_MULTI_VALUED_ATTRIBUTES
print("welcome emails:", settings.get("sendWelcomeEmailToNewUsers"))const response = await fetch(
"https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
{ method: "POST", headers, body: "{}" }
);
const { scimSettings = {} } = await response.json();
console.log("rolesFormat:", scimSettings.rolesFormat);req, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/findSCIMSettingsForOrg",
strings.NewReader("{}"))
req.Header.Set("x-auth-scheme", "api-token")
req.Header.Set("x-auth-apikey", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
// ... decode response.scimSettingsRole format compatibility
Rhombus accepts SCIM role assertions in two shapes via rolesFormat:
| Value | Shape | Typical IdP |
|---|---|---|
LIST_OF_STRINGS | "roles": | Okta, OneLogin, Google |
LIST_OF_MULTI_VALUED_ATTRIBUTES | "roles": | Azure AD / Entra |
If users are being created but their roles aren't assigned correctly, verify this setting against what your IdP actually sends.
Update SCIM settings
updateSCIMSettingsForOrg changes SCIM behavior without re-issuing the bearer token:
response = requests.post(
"https://api2.rhombussystems.com/api/org/updateSCIMSettingsForOrg",
headers=headers,
json={
"sendWelcomeEmailToNewUsers": False,
"sendWelcomeEmailToNewRhombusKeyUsers": True,
"addUsersOnRoleMismatch": True,
},
)
response.raise_for_status()Rotate or revoke the SCIM bearer token
To rotate: revoke, then set up again. Your IdP must be updated with the new token in the same maintenance window or provisioning will fail.
# 1. Revoke current access
requests.post(
"https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
headers=headers,
json={},
).raise_for_status()
# 2. Issue a new token with the same options as before
new = requests.post(
"https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
headers=headers,
json={
"sendWelcomeEmailToNewUsers": True,
"sendWelcomeEmailToNewRhombusKeyUsers": True,
"addUsersOnRoleMismatch": False,
},
).json()
new_token = new["token"]
# 3. Push new_token into your IdP's SCIM bearer-token field.// 1. Revoke
await fetch("https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
{ method: "POST", headers, body: "{}" });
// 2. Re-issue
const setupResp = await fetch(
"https://api2.rhombussystems.com/api/org/setupSCIMAccessForOrg",
{
method: "POST",
headers,
body: JSON.stringify({
sendWelcomeEmailToNewUsers: true,
sendWelcomeEmailToNewRhombusKeyUsers: true,
addUsersOnRoleMismatch: false,
}),
}
);
const { token: newToken } = await setupResp.json();
// 3. Update IdP with newToken.revokeReq, _ := http.NewRequest("POST",
"https://api2.rhombussystems.com/api/org/revokeSCIMAccessForOrg",
strings.NewReader("{}"))
// set headers, execute ...
// Then setup again to get a new token (see earlier example).Revoking SCIM immediately stops your IdP from syncing users. Existing Rhombus users are unaffected — they remain active and can still sign in via SAML — but any IdP changes (new hires, deprovisioned users) won't propagate until SCIM is restored.
IdP-specific setup notes
The API calls above are the same across every IdP. What differs is where to paste the Rhombus values in your IdP's console. These notes capture what customers most often need.
IdP consoles change their UI frequently. Treat these as starting points and fall back to the IdP's own documentation if a menu has moved.
Okta
SAML. Create a new SAML 2.0 application. For the SSO URL and Audience URI, use the values from your organization's Rhombus SAML ACS (visible in the Console under Settings → SSO / SAML). Download the Okta IdP metadata XML from the application's Sign On tab and pass it to updateSAMLSettingsV2 as idpMetaDataXml.
SCIM. In the Okta app's Provisioning tab, select SCIM 2.0. Set the SCIM connector base URL to the scimEndpointUrl from getScimDisplayInfo. Set Authentication Mode to HTTP Header, with Authorization: Bearer <scim-token>. Set rolesFormat to LIST_OF_STRINGS.
Azure AD / Microsoft Entra
SAML. Create a new Enterprise Application → Non-gallery. On Single sign-on, choose SAML and import Rhombus's SP metadata. Download the Federation Metadata XML from Azure and pass it to updateSAMLSettingsV2.
SCIM. On Provisioning, choose Automatic. Use the azureScimEndpointUrl (not the standard endpoint) as the Tenant URL, and paste the bearer token from setupSCIMAccessForOrg as the Secret Token. Set rolesFormat to LIST_OF_MULTI_VALUED_ATTRIBUTES — Azure sends role assertions in this shape.
Google Workspace
SAML. From the Google Admin Console, add a custom SAML app targeting Rhombus. Download the Google IdP metadata and pass it to updateSAMLSettingsV2.
SCIM. Google Workspace supports SCIM for some apps via Automated user provisioning. Use the scimEndpointUrl with bearer token authentication. Set rolesFormat to LIST_OF_STRINGS.
OneLogin
SAML. Create a new SAML 2.0 connector; configure the ACS URL and Entity ID from Rhombus's SP metadata. Download the OneLogin IdP metadata XML and pass it to updateSAMLSettingsV2.
SCIM. OneLogin's SCIM v2 provisioning takes the standard scimEndpointUrl and a bearer token. Set rolesFormat to LIST_OF_STRINGS.
Auditing SSO events
Every SAML login attempt — success or failure — is written to the Rhombus audit log, as are changes to SAML configuration itself. Pull these events via POST /api/report/getAuditFeed.
Audit event types relevant to SSO:
| Event type | Fires when |
|---|---|
SAML_LOGIN_WEB | A user successfully signs in via SAML on the Console |
SAML_LOGIN_FAILURE_WEB | A SAML sign-in failed on the Console |
SAML_LOGIN_MOBILE | A user signed in via SAML on a Rhombus mobile app |
SAML_LOGIN_FAILURE_MOBILE | A SAML sign-in failed on a Rhombus mobile app |
RHOMBUS_KEY_SAML_LOGIN | A user signed in via SAML on the Rhombus Key mobile app |
UPDATE_INTEGRATION_SAML | SAML configuration itself was changed |
Stream UPDATE_INTEGRATION_SAML events into your SIEM to detect unauthorized changes to SSO configuration, and alert on any SAML_LOGIN_FAILURE_* spike to catch broken rotations fast.
Troubleshooting
`updateSAMLSettingsV2` succeeds but users can't sign in
Most often an issue with the metadata XML itself rather than the API call.
- Verify the XML is well-formed and contains a current signing certificate — an expired cert in the metadata blocks every assertion.
- Verify the entity ID in the metadata matches what Rhombus expects (visible in the Console under Settings → SSO).
- Verify JIT is enabled if this is the first sign-in for these users and SCIM hasn't synced them yet — otherwise Rhombus has no user to map the assertion to.
- Check
UPDATE_INTEGRATION_SAMLaudit events to confirm the change landed as intended.
SCIM users are created but their roles are wrong
This is almost always rolesFormat mismatch. Call findSCIMSettingsForOrg, verify the value, and cross-reference against the role format compatibility table. Azure AD needs LIST_OF_MULTI_VALUED_ATTRIBUTES; most others need LIST_OF_STRINGS.
SCIM setup returns `scimAccessAlreadySetupFailure: true`
SCIM is already configured. Either (a) call revokeSCIMAccessForOrg and re-run setup to get a fresh token, or (b) call updateSCIMSettingsForOrg to modify options without touching the token.
SCIM provisioning stopped working after rotation
The IdP is still using the old bearer token. After revokeSCIMAccessForOrg + fresh setupSCIMAccessForOrg, the new token must be pasted into the IdP's provisioning config. Do both in one maintenance window to avoid a sync gap.
Locked out of SAML — can't sign in, no API key handy
Use a break-glass account with bypassSaml: true and a Rhombus-native password. If none exists, contact Rhombus Support. This is why break-glass access is a prerequisite, not a nice-to-have.
JIT creates users with no role
Set addUsersOnRoleMismatch: false to reject users whose IdP role doesn't map, forcing the IdP operator to fix the assertion. Set it to true if you prefer to create the user and assign a role in Rhombus after the fact. Pick deliberately — the two behaviors are mutually exclusive.
Next steps
Build third-party apps that authenticate Rhombus users (OAuth 2.0, separate from workforce SSO)
Full schema for every endpoint used in this guide (Org tag)
Understand request limits for scripted rotations and audits
Get help with SSO and SCIM configuration.