> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/organizations-and-access/sso-scim.md).

# SSO and SCIM

Enterprise identity is tenant-scoped. One tenant can have one OIDC or SAML provider, one or more assigned email domains, time-limited invitations, and multiple independently revocable SCIM bearer tokens.

Open `/<locale>/dashboard/admin/identity` to manage **Provider**, **Invitations**, and **SCIM**.

## Before you begin

* Use an `admin` or `super_admin` account in the target tenant.
* Confirm the public API and console origins with the operator.
* Reserve the organization's email domains. A domain can belong to only one enterprise provider across the deployment.
* Decide whether new users require an invitation or may be created by JIT.
* Store client secrets, certificates, invitation links, and bearer tokens only in approved systems.
* Use shared Redis across API replicas for OIDC/SAML callback state and replay protection. Keep public-origin and encryption configuration consistent across the deployment.

Provider client secrets and SAML signing certificates are encrypted at rest. Admin responses show configured state or a certificate fingerprint, never the stored secret or certificate value.

## OIDC workflow

1. On **Provider**, select **OpenID Connect**.
2. Enter a display name and comma-separated verified email domains.
3. Enter the HTTPS issuer, optional discovery URL, client ID, and client secret.
4. Choose **Enabled**, JIT policy, and default role.
5. Register this redirect URI at the identity provider:

```
https://<public-api-origin>/auth/enterprise/oidc/callback
```

6. Save, then test with an invited user before enabling JIT broadly.

When discovery URL is omitted, Kangal uses `<issuer>/.well-known/openid-configuration`. Authorization code flow uses PKCE S256, state, and nonce. Discovery, authorization, token, and JWKS endpoints must be safe public HTTPS destinations. The ID token must have an approved asymmetric signature, expected issuer and audience, required timestamps, matching nonce, subject, and a verified email in an assigned domain.

## SAML 2.0 workflow

1. Select **SAML 2.0**.
2. Enter the IdP entity ID, HTTPS HTTP-Redirect SSO URL, and PEM X.509 signing certificate.
3. Save the provider.
4. Import service-provider metadata from:

```
https://<public-api-origin>/auth/enterprise/saml/metadata/<provider-id>
```

5. Configure the assertion consumer service URL as:

```
https://<public-api-origin>/auth/enterprise/saml/callback
```

Kangal requires a signed assertion, matching audience and recipient, valid conditions, expected `InResponseTo`, a NameID or email attribute, and a unique assertion ID. Request state and assertion replay records are single-use.

Kangal uses an SP-initiated SAML flow. Unsolicited IdP responses are rejected. Use the normal Kangal logout together with the IdP's session controls.

## Invitations and JIT

An invitation selects `user`, `admin_readonly`, or `admin` and can expire from one hour to 30 days. Console invitations expire after 72 hours.

Issuing another pending invitation for the same tenant and email revokes the previous one. The acceptance URL contains a single-use credential. Acceptance atomically creates the tenant account and consumes the invitation; it cannot be replayed. If email delivery is unavailable, the create response can still provide the link for secure manual delivery.

Invitation issuance and email delivery are separate steps. The invitation record remains valid when background email delivery fails, so the operator must confirm delivery or transfer the returned acceptance link through an approved secure channel.

With JIT disabled, a new SSO identity must have a valid pending invitation. With JIT enabled, an eligible email in an assigned domain receives the provider's default role. Existing accounts in the same tenant are linked by email; an identity already linked to another tenant is rejected.

## SCIM provisioning

### Create and rotate a token

1. Open **SCIM** and select **Create token**.
2. Enter a descriptive name.
3. Copy the bearer value immediately; it is shown only once.
4. Configure the identity provider with the base URL shown in the console and:

```
Authorization: Bearer <one-time-visible-scim-token>
Content-Type: application/scim+json
```

The API can create tokens with an expiry from 1 to 730 days; the console uses 365 days. Rotation means creating a replacement, updating the directory, testing it, then revoking the old token. Inventory shows prefix, status, expiry, last use, and revocation time.

### Supported API

The base path is `/admin/scim/v2`.

| Resource  | Operations                                            |
| --------- | ----------------------------------------------------- |
| Discovery | `ServiceProviderConfig`, `ResourceTypes`, `Schemas`   |
| Users     | Create, list, get, replace, patch, and deactivate     |
| Groups    | Create, list, get, replace, patch members, and delete |

Lists use `startIndex` (starting at 1) and `count` (maximum 200). Supported filters are simple `eq` expressions:

* Users: `userName`, `externalId`, `id`, or `emails.value`.
* Groups: `displayName`, `externalId`, or `id`.

```bash
export KANGAL_URL='https://api.example.com'
export KANGAL_SCIM_TOKEN='<scim-token>'

curl --get "$KANGAL_URL/admin/scim/v2/Users" \
  --header "Authorization: Bearer $KANGAL_SCIM_TOKEN" \
  --header 'Accept: application/scim+json' \
  --data-urlencode 'filter=userName eq "alice"' \
  --data-urlencode 'startIndex=1' \
  --data-urlencode 'count=100'
```

### Tenant and account behavior

The SCIM token fixes the tenant. Query parameters, `X-Tenant-ID`, or payload `tenantId` cannot select another tenant. Cross-tenant attempts return a SCIM error.

SCIM-created users start with the direct `user` role and a generated password. Setting `active` to false or deleting a User deactivates the account and revokes all of that user's access sessions and refresh tokens in the tenant. Deletion is a soft deprovision, not physical user removal.

SCIM Groups maintain membership and appear in each SCIM User's `groups` attribute. They are separate from Kangal RBAC teams and do not automatically grant direct account roles or permission-matrix access.

## Audit and security

Provider changes, invitations, SCIM token lifecycle, and SCIM user/group mutations are audit logged. Raw invitation and SCIM bearer values are stored as keyed blind indexes and are redacted from audit records.

## Troubleshooting

| Symptom                                  | Check                                                                                            |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Domain is already assigned               | The domain belongs to another tenant provider; resolve ownership before retrying.                |
| Provider status is incomplete            | Supply the OIDC client secret or valid SAML signing certificate.                                 |
| OIDC metadata request fails              | Issuer/discovery endpoints must be HTTPS, reachable, and return matching issuer metadata.        |
| OIDC verified-email error                | Ensure the IdP emits `email` and `email_verified: true`.                                         |
| SAML response is rejected                | Verify audience, ACS recipient, request ID, conditions, signing certificate, and clock settings. |
| Invitation is invalid or expired         | Issue a new invitation; links are single-use and replacements revoke older pending links.        |
| SSO says user is not invited             | JIT is disabled and no valid invitation matches the verified email.                              |
| SCIM returns `401`                       | The bearer is incomplete, expired, or revoked. Use the full token, not its prefix.               |
| SCIM returns `invalidFilter`             | Use one supported field with a simple `eq` expression.                                           |
| Group sync did not change console access | SCIM Groups do not map to RBAC teams or direct roles.                                            |
| SCIM base URL cannot be produced         | The operator must configure an approved public API origin.                                       |

Before production launch, test the selected live IdP for metadata import, certificate or key rollover, exact attribute names, group behavior, logout expectations, and provider-specific SCIM filter requests.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/organizations-and-access/sso-scim.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
