feat: implement SCIM handler for SCIM 2.0 compliance (#25572)

Rewrites the SCIM 2.0 user provisioning handler to be RFC 7644
compliant. Verified against an external IdP Okta.

Behavior is OPT IN
This commit is contained in:
Steven Masley
2026-05-28 10:00:37 -05:00
committed by GitHub
parent 6df1536256
commit 4591212482
26 changed files with 2664 additions and 1091 deletions
+14 -14
View File
@@ -4520,9 +4520,9 @@ curl -X POST http://coder-server:8080/scim/v2/Users \
### Parameters
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------|----------|-------------|
| `body` | body | [coderd.SCIMUser](schemas.md#coderdscimuser) | true | New user |
| Name | In | Type | Required | Description |
|--------|------|------------------------------------------------------|----------|-------------|
| `body` | body | [legacyscim.SCIMUser](schemas.md#legacyscimscimuser) | true | New user |
### Example responses
@@ -4559,9 +4559,9 @@ curl -X POST http://coder-server:8080/scim/v2/Users \
### Responses
| Status | Meaning | Description | Schema |
|--------|---------------------------------------------------------|-------------|----------------------------------------------|
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [coderd.SCIMUser](schemas.md#coderdscimuser) |
| Status | Meaning | Description | Schema |
|--------|---------------------------------------------------------|-------------|------------------------------------------------------|
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [legacyscim.SCIMUser](schemas.md#legacyscimscimuser) |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
@@ -4638,10 +4638,10 @@ curl -X PUT http://coder-server:8080/scim/v2/Users/{id} \
### Parameters
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------|----------|----------------------|
| `id` | path | string(uuid) | true | User ID |
| `body` | body | [coderd.SCIMUser](schemas.md#coderdscimuser) | true | Replace user request |
| Name | In | Type | Required | Description |
|--------|------|------------------------------------------------------|----------|----------------------|
| `id` | path | string(uuid) | true | User ID |
| `body` | body | [legacyscim.SCIMUser](schemas.md#legacyscimscimuser) | true | Replace user request |
### Example responses
@@ -4730,10 +4730,10 @@ curl -X PATCH http://coder-server:8080/scim/v2/Users/{id} \
### Parameters
| Name | In | Type | Required | Description |
|--------|------|----------------------------------------------|----------|---------------------|
| `id` | path | string(uuid) | true | User ID |
| `body` | body | [coderd.SCIMUser](schemas.md#coderdscimuser) | true | Update user request |
| Name | In | Type | Required | Description |
|--------|------|------------------------------------------------------|----------|---------------------|
| `id` | path | string(uuid) | true | User ID |
| `body` | body | [legacyscim.SCIMUser](schemas.md#legacyscimscimuser) | true | Update user request |
### Example responses
+1
View File
@@ -538,6 +538,7 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
"workspace_agent_logs": 0
},
"scim_api_key": "string",
"scim_use_legacy": true,
"session_lifetime": {
"default_duration": 0,
"default_token_lifetime": 0,
+54 -51
View File
@@ -220,57 +220,6 @@
|--------------------|
| `prebuild_claimed` |
## coderd.SCIMUser
```json
{
"active": true,
"emails": [
{
"display": "string",
"primary": true,
"type": "string",
"value": "user@example.com"
}
],
"groups": [
null
],
"id": "string",
"meta": {
"resourceType": "string"
},
"name": {
"familyName": "string",
"givenName": "string"
},
"schemas": [
"string"
],
"userName": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|------------------|--------------------|----------|--------------|-----------------------------------------------------------------------------|
| `active` | boolean | false | | Active is a ptr to prevent the empty value from being interpreted as false. |
| `emails` | array of object | false | | |
| `» display` | string | false | | |
| `» primary` | boolean | false | | |
| `» type` | string | false | | |
| `» value` | string | false | | |
| `groups` | array of undefined | false | | |
| `id` | string | false | | |
| `meta` | object | false | | |
| `» resourceType` | string | false | | |
| `name` | object | false | | |
| `» familyName` | string | false | | |
| `» givenName` | string | false | | |
| `schemas` | array of string | false | | |
| `userName` | string | false | | |
## coderd.cspViolation
```json
@@ -6058,6 +6007,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"workspace_agent_logs": 0
},
"scim_api_key": "string",
"scim_use_legacy": true,
"session_lifetime": {
"default_duration": 0,
"default_token_lifetime": 0,
@@ -6657,6 +6607,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
"workspace_agent_logs": 0
},
"scim_api_key": "string",
"scim_use_legacy": true,
"session_lifetime": {
"default_duration": 0,
"default_token_lifetime": 0,
@@ -6817,6 +6768,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `redirect_to_access_url` | boolean | false | | |
| `retention` | [codersdk.RetentionConfig](#codersdkretentionconfig) | false | | |
| `scim_api_key` | string | false | | |
| `scim_use_legacy` | boolean | false | | |
| `session_lifetime` | [codersdk.SessionLifetime](#codersdksessionlifetime) | false | | |
| `ssh_keygen_algorithm` | string | false | | |
| `stats_collection` | [codersdk.StatsCollectionConfig](#codersdkstatscollectionconfig) | false | | |
@@ -17915,6 +17867,57 @@ Zero means unspecified. There might be a limit, but the client need not try to r
None
## legacyscim.SCIMUser
```json
{
"active": true,
"emails": [
{
"display": "string",
"primary": true,
"type": "string",
"value": "user@example.com"
}
],
"groups": [
null
],
"id": "string",
"meta": {
"resourceType": "string"
},
"name": {
"familyName": "string",
"givenName": "string"
},
"schemas": [
"string"
],
"userName": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|------------------|--------------------|----------|--------------|-----------------------------------------------------------------------------|
| `active` | boolean | false | | Active is a ptr to prevent the empty value from being interpreted as false. |
| `emails` | array of object | false | | |
| `» display` | string | false | | |
| `» primary` | boolean | false | | |
| `» type` | string | false | | |
| `» value` | string | false | | |
| `groups` | array of undefined | false | | |
| `id` | string | false | | |
| `meta` | object | false | | |
| `» resourceType` | string | false | | |
| `name` | object | false | | |
| `» familyName` | string | false | | |
| `» givenName` | string | false | | |
| `schemas` | array of string | false | | |
| `userName` | string | false | | |
## netcheck.Report
```json