SSO Troubleshooting
Audience: organization Owners and Admins debugging SSO sign-in failures, SCIM provisioning problems, or roles that do not follow the directory.
This page is provider-independent. For setup steps, see SSO Setup Overview.
Start from the symptom you are seeing and work down.
Sign-in fails
1. Find out what the user actually saw
The screen or error code narrows the cause more than anything else:
| What the user sees | Most likely cause |
|---|---|
| The Single Sign-On required page | Their email domain has SSO enforcement on and they tried a password sign-in. This is enforcement working as designed — they should use the Continue to sign in button. |
| A generic "Something went wrong" page from the sign-in screen | An invalid SAML signature, stale IdP metadata, or clock skew. Continue with steps 3 and 4. |
| They land back on the Routebase sign-in page with no error | The assertion arrived for a connection Routebase does not recognise. Usually the ACS URL in the IdP still points at a placeholder or at an old connection. |
| A redirect loop between Routebase and the IdP | Missing or wrongly formatted NameID. Set the NameID format to email address and the NameID value to the user's email. |
401 with code SSO_REQUIRED |
An API call from a session that enforcement blocked. |
401 with code MISSING_CLAIM and claim: "email" |
The IdP asserted no email. On Microsoft Entra ID this is almost always a user without a mailbox, with the email claim mapped to user.mail — map it to user.userprincipalname instead. |
403 with code SSO_JIT_DISABLED |
Just-in-time provisioning is off on the connection and the user has no membership yet. Either turn JIT on under Manage, or invite the user first. |
2. Check the connection itself
Under Settings → Single Sign-On, in the SSO Connections card:
- The status badge must read Active — not Draft, Disabled or Error.
- The row shows the last error message if the previous attempt failed. Read it before anything else.
- Click Test to reproduce the handshake yourself. If your own test succeeds while a real user fails, the difference is on the IdP side: that user is not assigned to the application, is outside the assigned population, or is suspended.
3. Check whether the IdP rotated its certificate
A connection that worked for months and then stopped, for everyone at once, is nearly always a signing-certificate rotation.
- If you configured a metadata URL, Routebase re-reads it. Open Manage and save the connection to force a refresh now.
- If you pasted metadata XML, nothing refreshes automatically. Download the current metadata from your IdP and paste the new XML into Manage. Sign-ins stay broken until you do.
4. Check the clock
SAML assertions are valid for a few minutes. If your IdP's clock is off by more than that, every sign-in fails and the errors look random. Confirm the IdP host is synchronised with NTP.
5. Check the verified domain — and when it was verified
- The user's email domain must appear under Settings → Domains as verified.
- Subdomains are not covered by their parent. If you verified
acme.comand the user signs in asalice@eu.acme.com, that domain needs verifying too. - If you verified the domain after creating the connection, sign-ins from it are not routed yet. The connection captures your verified domains at the moment it is saved. Open the connection under Manage and save it again — no field needs changing — to pick up domains verified since.
6. Read the audit log
Under Settings → Audit Log, set the event filter to SSO:
| Event | Meaning |
|---|---|
sso.login_success |
The handshake completed. |
sso.jit_denied |
The user had no membership and just-in-time provisioning was off. |
sso.enforcement_blocked |
A password sign-in was rejected on an enforced domain. |
sso.connection_test_started |
Someone ran the connection test. |
sso.connection_create_failed, sso.connection_updated, sso.connection_activated |
Configuration changes, with the actor who made them. |
Provisioning and role events sit under the User & Members filter instead, as user.jit_provisioned, user.role_changed_via_sso and user.role_changed_via_scim.
The table shows time, actor, event, result and target. Each entry also carries a structured details field with the specifics — which attributes were extracted, which group matched — and that field is only in the Export as JSON download, not in the table.
SCIM provisioning fails
What the error codes mean
Routebase returns RFC 7644 error documents as application/scim+json:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "400",
"scimType": "invalidFilter",
"detail": "Unsupported or malformed filter 'emails.value sw foo'."
}
| HTTP | scimType | What it means | What to do |
|---|---|---|---|
| 400 | invalidFilter |
Routebase supports only eq comparisons, on four attributes. |
Filter on userName, email, externalId or displayName with eq only. |
| 400 | invalidPath |
A PATCH operation names an attribute path Routebase does not recognise. | Restrict PATCH to active, name.givenName, name.familyName, displayName and emails. |
| 400 | invalidValue |
A required field is missing or has the wrong type. | Check the body against the RFC 7643 user or group schema. |
| 400 | invalidSyntax |
The body is not valid JSON. | Usually the IdP double-encoding the payload. |
| 401 | — | The bearer token is missing, unknown, revoked or expired. | Create a fresh token and paste it into the IdP. |
| 403 | — | The token does not belong to the organization in the URL. | Tokens are scoped to the organization that created them — check the <your-org-slug> in the base URL. |
| 404 | notFound |
The user or group does not exist, or was already deleted. | Safe to ignore for DELETE, which is idempotent. For PATCH or GET on a stale ID, rebuild the IdP's external-ID map. |
| 409 | uniqueness |
A user with that userName or externalId already exists. |
Update the existing user with PUT instead of creating a new one with POST. |
Reproduce it yourself with curl
If your IdP reports a failure it will not explain, run the same calls by hand. This is the fastest way to tell a Routebase problem from an IdP-configuration problem:
SCIM_TOKEN="rb_scim_..."
ORG_SLUG="acme"
BASE="https://api.routebase.dev/scim/v2/$ORG_SLUG"
# 1. Is the endpoint reachable? ServiceProviderConfig needs no authentication.
curl -s "$BASE/ServiceProviderConfig" | jq
# 2. Does the token work?
curl -s -H "Authorization: Bearer $SCIM_TOKEN" "$BASE/Users?count=5" | jq
# 3. Provision a test user.
curl -s -X POST -H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"smoke@acme.com",
"name":{"givenName":"Smoke","familyName":"Test"},
"emails":[{"value":"smoke@acme.com","type":"work","primary":true}],
"active":true,
"externalId":"smoke-123"
}' "$BASE/Users" | jq
If these succeed but your IdP still fails, the problem is in the IdP's SCIM configuration — most often a wrong base URL or the wrong organization slug.
Rotating a token without downtime
Both the old and the new token stay valid until you revoke the old one, so rotate in this order:
- Create a new token under Settings → Single Sign-On → SCIM Provisioning Tokens.
- Paste it into the IdP's SCIM configuration.
- Trigger a sync and confirm it succeeds.
- Then revoke the old token.
Removing a user in the IdP does not deactivate them
When a user is removed through SCIM, Routebase deactivates their membership, revokes the organization-scoped API keys they own, revokes their active sessions, and records a scim.user_deprovisioned event.
| Symptom | Cause |
|---|---|
| The user can still sign in through SSO | The IdP only unassigned the application rather than removing or suspending the user. An unassignment is not communicated over SAML — deactivation needs SCIM. |
| The membership is deactivated but the session is still alive | Session revocation is best-effort and does not block deprovisioning. The session ends when it next refreshes. |
| Nothing happened at all | Check Settings → Audit Log, filter SCIM, and look for scim.user_deprovisioned. If it is absent, the IdP never sent the request — check its provisioning log and that Delete/Suspend actions are enabled. |
Google Workspace has no SCIM client for third-party apps, so none of this applies there — see the Google Workspace guide for what happens instead.
Group role mappings do not apply
Roles are re-evaluated when a user is provisioned just-in-time, on subsequent sign-ins, and on SCIM group membership changes.
| Symptom | Cause |
|---|---|
| Everyone lands on the default role and no mapping ever fires | The IdP is not sending group names. On Entra ID this is the number-one cause: either no group claim is configured, or it emits object IDs (GUIDs). The Entra fix is both parts — source Cloud-only group display names and the Emit group names for cloud-only groups checkbox. |
| The mapping exists but the role does not change after signing in | Re-evaluation is throttled to roughly five minutes per user. Beyond that, a silent token refresh never re-reads the IdP's groups — the user has to sign out fully and sign in again. |
routebase-Admins does not fire but routebase-admins does |
Routebase matches case-insensitively, so this is the IdP sending a different name than you expect, not a casing bug. Export the audit log as JSON and read the matchedGroup field to see the name that actually arrived. |
| Several groups match and the wrong role wins | The highest priority wins. When two mappings share a priority the outcome is arbitrary — give every mapping a distinct priority. |
| Removing someone from a group does not downgrade them | The resolver re-evaluates from the complete group set in each assertion. If the IdP sends only deltas, it never sees the removal. |
A role change writes user.role_changed_via_sso or user.role_changed_via_scim — but only when the role actually changed. No event after a sign-in therefore means the resolver ran and found nothing to change, which is itself the answer: the group did not arrive, or it matched no mapping. The JSON export shows matchedGroup, matchedPriority and fallbackUsed for each of these events.
Still stuck
Contact support with:
- Your organization slug.
- The approximate time of the failure, in UTC.
- The exact error the user saw, including any code (
SSO_REQUIRED,SSO_JIT_DISABLED,MISSING_CLAIM, or a SCIMscimType). - Whether it affects every user or only some — and if only some, what those accounts have in common.
- The connection's Connection ID from the connection's Manage dialog.
Setup guides: Overview · Okta · Microsoft Entra ID · Google Workspace · OneLogin · Ping Identity