Skip to content
Documentation

SCIM API reference

SSOGEN speaks SCIM 2.0 in two directions. As a server, it lets an identity source such as Microsoft Entra ID or Okta create, update and deactivate people and groups in SSOGEN. As a client, it creates and updates accounts in an application that has a SCIM interface. This page is the reference for both: every endpoint, attribute, filter, operation and error answer.

To set either direction up in the console, follow Inbound provisioning with SCIM or Outbound provisioning. This page does not repeat those steps.

Item Value
Base URL Your SSOGEN address followed by /scim, for example https://sso.example.com/scim. There is no version segment in the path.
Authentication Authorization: Bearer <provisioning token> on every request, the discovery endpoints included.
Request body type application/scim+json or application/json
Answer type application/scim+json, with Cache-Control: no-store
Resources User and Group
PATCH Supported, at most 200 operations in one request
Filter Supported, eq only (section 5)
Bulk, sort, ETag preconditions, password change Not supported
Method and path What it does
GET /scim/ServiceProviderConfig What the server supports
GET /scim/ResourceTypes The two resource types
GET /scim/Schemas, GET /scim/Schemas/{id} The User and Group schemas
GET /scim/Users List people, or find one with filter
POST /scim/Users Create a person
GET /scim/Users/{id} Read a person
PUT /scim/Users/{id} Replace a person’s profile and status
PATCH /scim/Users/{id} Change part of a person
DELETE /scim/Users/{id} Remove a person (the account is archived, see section 4.5)
GET /scim/Groups List groups, or find one with filter
POST /scim/Groups Create a group
GET /scim/Groups/{id} Read a group
PUT /scim/Groups/{id} Replace a group’s members
PATCH /scim/Groups/{id} Add or remove members
DELETE /scim/Groups/{id} Delete a group

Send the provisioning token an administrator issued for this client as a bearer token. The token starts with ssogen_scim_. A browser session is never accepted on these endpoints.

GET /scim/Users?filter=userName%20eq%20%22jane.smith%40acme.example%22 HTTP/1.1
Host: sso.example.com
Authorization: Bearer ssogen_scim_<your token>
Accept: application/scim+json

A request with no token, or with a token that is wrong or revoked, is answered:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="SSOGEN SCIM"
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail": "A valid provisioning token is required.",
"status": "401"
}

Issuing and revoking a token is recorded in the audit log as scim_client.issued and scim_client.revoked.

GET /scim/ServiceProviderConfig answers with these capabilities. A client that reads them configures itself correctly.

Capability Answer
patch supported: true
bulk supported: false, maxOperations: 0, maxPayloadSize: 0
filter supported: true, maxResults: 200
changePassword supported: false
sort supported: false
etag supported: false
authenticationSchemes One scheme: type oauthbearertoken, name OAuth Bearer Token, primary: true

GET /scim/ResourceTypes lists User (endpoint /Users) and Group (endpoint /Groups). GET /scim/Schemas/{id} answers 404 with the detail No such schema. for any other identifier.

Attribute Notes
schemas Always ["urn:ietf:params:scim:schemas:core:2.0:User"]
id Issued by SSOGEN. Never changes. Use it in every later request.
externalId Your identifier for the person. Present when one was set. Unique.
userName Required. Unique. The name the person signs in with.
name Always present. Holds givenName and familyName when set, and formatted, which carries the display name.
displayName Present when set
emails Present when the person has an address: one entry with value, "type": "work" and "primary": true. SSOGEN keeps one address per person.
active true only when the account is active. A disabled or locked account answers false.
groups Read-only. Present only when the person is a member of a group: value, display and $ref for each.
meta resourceType, created, lastModified, location and version. location is a path relative to your SSOGEN address, for example /scim/Users/<id>.
POST /scim/Users HTTP/1.1
Host: sso.example.com
Authorization: Bearer ssogen_scim_<your token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"externalId": "00u1abcd",
"userName": "jane.smith@acme.example",
"name": { "givenName": "Jane", "familyName": "Smith" },
"displayName": "Jane Smith",
"emails": [{ "value": "jane.smith@acme.example", "type": "work", "primary": true }],
"active": true
}
HTTP/1.1 201 Created
Location: /scim/Users/3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11",
"externalId": "00u1abcd",
"userName": "jane.smith@acme.example",
"name": { "givenName": "Jane", "familyName": "Smith", "formatted": "Jane Smith" },
"displayName": "Jane Smith",
"emails": [{ "value": "jane.smith@acme.example", "type": "work", "primary": true }],
"active": true,
"meta": {
"resourceType": "User",
"created": "2026-11-09T10:15:30Z",
"lastModified": "2026-11-09T10:15:30Z",
"location": "/scim/Users/3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11",
"version": "W/\"1\""
}
}

Rules for a create:

  • userName is required. Without it the answer is 400, scimType invalidValue, detail userName is required.
  • When active is left out, the person is created active.
  • When several addresses are sent in emails, SSOGEN stores the one marked primary, or the first one when none is marked.
  • A request with no body is answered 400, scimType invalidSyntax, detail No body.

PUT /scim/Users/{id} replaces the display name, given name, family name, primary email address and status. It does not change userName or externalId. When active is left out of a PUT, the person is made active, so always send it.

The body is a SCIM PatchOp message. op is add, replace or remove, in any letter case. Attribute names are not case-sensitive, and a path may carry the full schema prefix.

PATCH /scim/Users/3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11 HTTP/1.1
Host: sso.example.com
Authorization: Bearer ssogen_scim_<your token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "active", "value": false }
]
}

The answer is 200 with the whole User resource, now with "active": false.

An operation with no path carries an object, which is merged:

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "value": { "displayName": "Jane Baker", "name": { "familyName": "Baker" } } }
]
}
Path SSOGEN acts on Effect
active Activates or deactivates the account. remove deactivates it.
displayName Sets the display name. remove clears it.
name.givenName, name.familyName Sets or clears the name part
emails or emails.value Sets the address. The value may be a string, one object with value, or a list of such objects (the one marked primary wins, otherwise the first).

Every other path is accepted and ignored, so a client that also sends attributes SSOGEN does not keep is not refused.

A PATCH is all or nothing: when one operation is refused, nothing is changed.

DELETE /scim/Users/{id} answers 204 with no body. The account is archived, not erased:

  • Every later request for that id answers 404 with the detail No such user.
  • The person leaves every list, filter result, totalResults count and group member list.
  • The userName and externalId stay taken. A create that names either is answered 409 (section 7), and an administrator can restore the archived account in the SSOGEN console.

To suspend a person and keep the record visible to your client, send active: false instead of DELETE.

Situation Answer
The account’s name and email address are owned by a connected directory Profile values in a PUT are ignored and active is applied. A PATCH that changes them is answered 400, scimType mutability: This user's name and email are managed by the directory <name> and are read-only here. Send only active to change the account's status.
The account holds an SSOGEN administrator role and this client did not create it 403: This account holds a SSOGEN administrator role and was not provisioned by this client. A Super Admin changes it in the SSOGEN console.
The account holds an administrator role and the request changes its user name or email 403: This account holds a SSOGEN administrator role. A SCIM client may end it or rename it, but not change its user name or email; a Super Admin does that in the SSOGEN console.
Deactivating or removing the account would leave nobody able to sign in to the admin console 409: Nobody else could sign in to the SSOGEN admin console under its sign-in policy, so this account was not deactivated. A Super Admin gives another account that can sign in to the console the Super Admin role first. Nothing was changed.

These answers carry no scimType. They are final for that request: retrying does not help until an administrator acts. Each one is recorded in the audit log (section 8).

GET /scim/Users?startIndex=1&count=100 HTTP/1.1
Host: sso.example.com
Authorization: Bearer ssogen_scim_<your token>
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 2,
"startIndex": 1,
"itemsPerPage": 2,
"Resources": [ { "...": "a User resource" }, { "...": "a User resource" } ]
}
Parameter Behaviour
startIndex First result to return, counted from 1. Default 1.
count Page size. Default 100. A value above 200 is treated as 200. A value of 0 or less returns totalResults and an empty Resources list.
filter One comparison, at most 512 characters

itemsPerPage is the number of resources in this answer.

The only form accepted is <attribute> eq "<value>". The attribute name and eq are not case-sensitive, and the value must be in double quotes.

Resource Attributes you can filter on
Users userName, externalId, emails.value, displayName
Groups displayName, externalId

A filtered read finds no resource or one. No match is a normal 200 answer with "totalResults": 0, which is how a client learns that it must create the person.

Any other filter is answered 400 with scimType invalidFilter, and the detail says what was wrong:

Detail Cause
the filter is empty filter= with no value
the filter is longer than 512 characters Filter too long
expected <attribute> eq "<value>", got: … Not three parts
only the eq operator is supported, not "co" Another operator (co, sw, and, …)
the value must be in double quotes, got: … Unquoted value
the value is empty eq ""
filter on "department" is not supported; this directory filters on userName, externalId, emails.value and displayName Another attribute
Attribute Notes
schemas Always ["urn:ietf:params:scim:schemas:core:2.0:Group"]
id Issued by SSOGEN
externalId Present when set
displayName Required. Unique.
members Always present, empty when the group has nobody. Each member has value (the person’s SSOGEN id), display and $ref.
meta As for a User, with resourceType Group
POST /scim/Groups HTTP/1.1
Host: sso.example.com
Authorization: Bearer ssogen_scim_<your token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Finance",
"externalId": "grp-finance",
"members": [{ "value": "3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11" }]
}
HTTP/1.1 201 Created
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "8a4d1b7c-0e6f-4a39-b1c2-5d9e3f7a6b20",
"externalId": "grp-finance",
"displayName": "Finance",
"members": [
{
"value": "3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11",
"display": "Jane Smith",
"$ref": "/scim/Users/3f0c2c1e-5d2a-4c53-9f0e-2a7d6b1f4e11"
}
],
"meta": {
"resourceType": "Group",
"created": "2026-11-09T10:20:00Z",
"lastModified": "2026-11-09T10:20:00Z",
"location": "/scim/Groups/8a4d1b7c-0e6f-4a39-b1c2-5d9e3f7a6b20",
"version": "W/\"1\""
}
}

PATCH /scim/Groups/{id} acts on members only.

Operation Effect
{"op":"add","path":"members","value":[{"value":"<user id>"}]} Adds the listed people
{"op":"replace","path":"members","value":[…]} Makes the list the whole membership
{"op":"remove","path":"members[value eq \"<user id>\"]"} Removes one person
{"op":"remove","path":"members"} with no value Removes everyone

PUT /scim/Groups/{id} replaces the member list. It does not rename the group.

DELETE /scim/Groups/{id} answers 204 and deletes the group. This is recorded as directory.group.deleted.

Situation Answer
A member value that is not in the form of an SSOGEN id Left out without an error
A member value in the right form that names no current person (for example an archived account) 400, scimType invalidValue, detail user_missing. Nothing is changed.
The group’s membership is set by a rule in SSOGEN 400, scimType mutability, detail group_membership_is_ruled
The change would add or remove an SSOGEN administrator this client did not create 403: This change would add or remove a SSOGEN administrator this client did not provision. A Super Admin changes their groups in the SSOGEN console.
displayName missing on create 400, invalidValue, detail displayName is required
A group with that name exists 409, uniqueness, detail a group with that displayName already exists

Every error uses the SCIM error message. status is a string, as the specification requires.

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType": "uniqueness",
"detail": "a user with that userName already exists",
"status": "409"
}
Status scimType When What the client should do
400 invalidSyntax No body (No body.), or a PATCH that cannot be read Fix the request. Do not retry unchanged.
400 invalidFilter A filter SSOGEN does not support (section 5) Use an eq filter on a supported attribute
400 invalidValue A required value is missing or a member does not exist Fix the value
400 mutability The attribute is owned by a directory, or the group is rule-managed Send only what the client may change
401 none Missing, wrong or revoked token Issue a new token in the console
403 none A protected administrator account (sections 4.6 and 6.4) An administrator acts in the console
404 none No such user., No such group., No such schema. Look the resource up again with a filter
409 uniqueness The userName, externalId or group name is taken Find the existing resource and update it
409 none The change would lock everyone out of the admin console An administrator acts in the console
503 none Try again later. Retry after a pause

The two 409 uniqueness details for a user name are a user with that userName already exists and a user with that userName was archived and the name is not reused; an administrator can restore the account in the SSOGEN console. The same two exist for externalId.

PATCH details, all with 400 and invalidSyntax:

Detail Cause
the request has no body Empty request
a PATCH must carry a non-empty Operations array Operations missing or empty
more than 200 operations in one request Split the request
an operation is not an object, an operation has no op, unknown op: … Malformed operation
a remove operation must name a path remove with no path
an operation with no path must carry an object to merge add or replace with no path and a value that is not an object
unbalanced brackets in path: … A path with [ that does not end in ]
only a [value eq "..."] filter is supported in a path, not: … A path filter on something other than value
only the eq operator is supported in a path filter, not: … Another operator inside the brackets
the value in a path filter must be quoted: …, the value in a path filter is empty: … Malformed filter value
expected a boolean, got nothing, expected a boolean, got: … active with a value that is not true or false
Event Recorded when
scim_client.issued, scim_client.revoked An administrator issues or revokes a provisioning token
directory.user.provisioned A SCIM client creates or updates a person
directory.user.deprovisioned A SCIM client deactivates or removes a person. The result is denied when the request was refused because it would have locked everyone out of the admin console.
admin.target_action_refused A request on a protected administrator account was refused
directory.group.deleted A group was deleted

See Audit log for searching and exporting, and the Audit event reference for the fields.

9. Outbound: what SSOGEN sends to an application

Section titled “9. Outbound: what SSOGEN sends to an application”

When SSOGEN provisions into an application, it is the SCIM client. Use this section to check that the application’s SCIM interface will work, or to read its access log during a first run.

Item Value
Authentication Authorization: Bearer <the token you saved for the application>
Accept application/scim+json, application/json
Content-Type application/scim+json, on requests with a body
Time allowed 15 seconds for each request
Answer size Up to 1,000,000 bytes. A larger answer is refused.
Redirects Never followed. The base URL must answer directly.
Step Request
Find a person GET <base>/Users?filter=userName eq "<value>"
Create a person POST <base>/Users
Update a person PATCH <base>/Users/<id> with a PatchOp message
Deactivate a person PATCH <base>/Users/<id> with {"op":"replace","path":"active","value":false}
Find a group GET <base>/Groups?filter=displayName eq "<name>"
Read a group GET <base>/Groups/<id>
Create a group POST <base>/Groups with displayName and members (each {"value":"<id>"})
Update a group PATCH <base>/Groups/<id>: replace on displayName, add on members, and one PATCH for each removed member with {"op":"remove","path":"members[value eq \"<id>\"]"}

SSOGEN never sends DELETE or PUT to an application. A person who loses access is deactivated, and the account stays in the application.

The application must therefore support: an eq filter on userName and on displayName, PATCH with add, replace and remove, and the members[value eq "<id>"] path.

With the default mapping, SSOGEN sends:

{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jane.smith@acme.example",
"name": { "givenName": "Jane", "familyName": "Smith" },
"emails": [{ "value": "jane.smith@acme.example", "type": "work" }],
"active": true
}

The application must answer with the resource and its id. SSOGEN keeps that id and uses it for every later PATCH.

The default mapping sends userName from the SSOGEN user name, name.givenName, name.familyName, and emails[type eq "work"].value from the email address. You can change it per application, with at most 32 entries. A fixed value is at most 256 characters.

Group Target attributes you can map to
Core userName, displayName, nickName, title, userType, preferredLanguage, locale, timezone, profileUrl, externalId
Name The parts of name, for example name.givenName and name.familyName
Email emails[type eq "work"].value, and the same with home or other
Phone phoneNumbers[type eq "work"].value, and the same with mobile, home or other
Enterprise extension (urn:ietf:params:scim:schemas:extension:enterprise:2.0:User) employeeNumber, costCenter, organization, division, department

9.5 How SSOGEN reads the application’s answers

Section titled “9.5 How SSOGEN reads the application’s answers”
The application answers SSOGEN does
A search with no match, or 404 to a search Treats the person or group as absent and creates it
A search with more than one match Stops for that person: the application holds more than one match
A resource with no id Stops for that person: the application returned a resource with no id
429, 502, 503, 504, or no answer, to a GET or PATCH Tries once more after 1 second
Any failure to a POST Does not retry, so a person is never created twice
401 or 403 Stops the whole run. Check the token saved for the application.
404 for an account SSOGEN had linked Forgets the link and looks the person up again by user name
400 with scimType noTarget when removing a member Counts the member as removed
Any other error status Reports the application answered <status> (<scimType>)

Other messages you can meet on a run: the application could not be reached, the application returned an oversized response and the application returned a response that is not SCIM. The outcome of each run is shown on the application’s provisioning tab, see Outbound provisioning.