Skip to Content
KeuralDocs
Developers

SSO·SCIM integration spec

Values and behavior specification for OIDC, SAML 2.0, and SCIM 2.0 integration.

For the setup steps on screen, see SSO and SCIM.

In the tables, {API} is the Keural API address for the environment you use (for example, https://api.keural.ai). Use the exact address shown on the Organization management → SSO screen.

Registration values summary

ItemValue
OIDC redirect URI{API}/api/sso/callback
OIDC·SAML sign-in start{API}/api/sso/{orgId}/login
SAML SP EntityID{API}/api/sso/saml/metadata
SAML ACS URL{API}/api/sso/saml/callback
SCIM Base URL{API}/scim/v2

Sign-in always starts from Keural (SP-initiated). When you enter an email address from a registered domain on the sign-in screen, you are taken to the sign-in start address. On success, you go to the Keural home screen. On failure, you go to /login?error=sso.

OIDC

ItemBehavior
FlowAuthorization Code
authorize requestresponse_type=code, client_id, redirect_uri, scope=openid email profile, state, nonce
state · nonceOne-time use and valid for 10 minutes. If the sign-in window stays open for more than 10 minutes, you sign in again from the beginning.
Token exchangePOST to the token endpoint, application/x-www-form-urlencoded. Client authentication is client_secret_post (client_id and client_secret in the body).
ID token signatureOnly RS256 is accepted. The key is found in jwks_uri by kid.
ID token validationSignature, exp, aud includes client_id, nonce matches, and iss matches the Issuer URL (a trailing / is ignored)
EmailThe email claim in the ID token. If it is missing, the userinfo endpoint is called with Authorization: Bearer <access_token> to read email.
NameThe name claim in the ID token
EndpointsFound at /.well-known/openid-configuration under the Issuer URL. For an IdP that cannot be found, enter the authorization, token, JWKS, and userinfo addresses directly under Show advanced settings.
Time limit15 seconds per IdP call

The IdP application must allow client_secret_post. If it allows only client_secret_basic or private_key_jwt, the token exchange fails.

SAML 2.0

ItemBehavior
RequestThe AuthnRequest is sent with the HTTP-Redirect binding. The request is not signed.
Request contentsDestination = IdP SSO URL, AssertionConsumerServiceURL = ACS URL, ProtocolBinding = HTTP-POST, Issuer = SP EntityID, NameIDPolicy Format=…:nameid-format:unspecified, AllowCreate=true
ResponseHTTP-POST binding, with SAMLResponse and RelayState. RelayState must be returned exactly as Keural sent it.
SignatureThe Response or the Assertion must carry a valid signature. Only the certificate registered on the screen is used to verify it.
AssertionExactly one assertion must be in the response. Encrypted assertions (EncryptedAssertion) are not accepted.
StatusStatusCode is urn:oasis:names:tc:SAML:2.0:status:Success
IssuerIf you entered an IdP EntityID, it must match the assertion Issuer.
ConditionsNotBefore and NotOnOrAfter (clock tolerance 300 seconds), Audience = SP EntityID
SubjectConfirmationDataRecipient = ACS URL, NotOnOrAfter (clock tolerance 300 seconds), InResponseTo = the request ID that Keural sent
EmailAn attribute whose Name or FriendlyName is one of the following (case-insensitive): email, mail, emailAddress, E-Mail-Addresses, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress. If none is found, the NameID containing @ is used.
NamedisplayName, name, cn, http://schemas.microsoft.com/identity/claims/displayname
CertificateOne X.509 certificate, in PEM or Base64 (DER). To replace it, enter the new certificate and save.
MetadataInstead of uploading the IdP metadata XML, enter three values: the IdP EntityID, the IdP SSO URL, and the certificate.

User matching

ItemBehavior
Criteria for sending to SSOThe part after @ in the email address exactly matches one entry in the Email domains list (case-insensitive). Subdomains must be registered separately.
Finding the accountThe Keural account is found by the email address (lowercase) that the IdP returned.
When no account existsIf Auto-create users on first login (JIT) is on, the account is created. If it is off, sign-in is refused.
Joining the organizationIf the user is not an organization member, they join as a Member. An account whose seats are full or that belongs to another organization can sign in but does not join.
Conditions for saving an email domainDomains verified by DNS TXT. Public email domains are excluded.

Domain verification

ItemValue
Record typeTXT
HostThe registered domain as is (for example, acme.com). Do not use a prefixed subdomain.
Valuekeural-verify=<UUID>, exactly as shown on the screen
Check timingLooked up once when you press Confirm verification.

SCIM 2.0

ItemValue
Base URL{API}/scim/v2
AuthenticationAuthorization: Bearer <SCIM token>. The token starts with scim_ and is shown only once when issued.
Content-TypeRequest: application/scim+json or application/json. Response: application/scim+json
Status codesReturned as the actual HTTP status codes. Error bodies use the SCIM Error format (schemas, status, detail, scimType).

Endpoints

MethodPathBehavior
GET/UsersList. filter=userName eq "…", startIndex (default 1), count (default 100, maximum 200)
GET/Users/{id}Get one user
POST/UsersCreate (201). Returns 409 if the same email already exists.
PATCH/Users/{id}Change active, displayName, name.formatted, name.givenName
PUT/Users/{id}Applies displayName, name, and active. If active is omitted, the user is treated as active.
DELETE/Users/{id}Suspends the account (204). Data is not deleted.
GET/Groups, /Groups/{id}Get the two fixed groups. filter=displayName eq "…"
PATCH/Groups/{id}Add, remove, or replace members
GET/ServiceProviderConfig, /ResourceTypes, /SchemasGet supported features

User attributes

AttributeUse
userNameEmail address. If missing, emails[0].value is used.
displayName · name.formatted · name.givenName+name.familyNameDisplay name
activefalse suspends the user (blocks sign-in), true restores the user
idKeural user ID. Included in the response.

externalId is not stored. To find a user in the IdP, use the userName filter.

Groups

iddisplayNameWhen a member is addedWhen a member is removed
keural-adminsKeural AdminsAdminMember
keural-membersKeural MembersMemberNo change

The role of the organization owner is not changed by SCIM. Creating or deleting groups (POST or DELETE /Groups) returns 501. The value of a group member is the Keural user ID (id from /Users).

Supported scope

FeatureSupported
PATCHYes
FiltersuserName eq, displayName eq
Bulk · sorting · ETag · password changeNo

Errors

StatusscimTypeCause
400invalidValueBoth userName and emails are missing
401—Token missing or incorrect, or SCIM provisioning is turned off
404—The user or group does not belong to this organization
409uniquenessAn account with the same email already exists, or seats are exceeded
501—Creating or deleting groups

On this page