Replace a user's direct roles
PUT /v1/users/{user_id}/roles · permission users:write
Replaces the user's direct environment roles with role_ids (the full set, at most 50; an empty array removes them). Organization roles cannot be assigned directly; assign them through an organization membership. Writing the same set again changes nothing. A change marks the user's refresh token families with roles_changed, so the next refresh carries the new roles, and is audited as user.updated with change=roles. If the set contains a privileged (is_privileged) role, whether newly added or kept, the credential also needs roles:write; removing a privileged role from the set needs only users:write.
Request
| Field | Type | Required | Description |
|---|---|---|---|
user_id |
path | yes | User ID (usr_…). |
role_ids |
string[] | yes | The full set of environment role IDs (rol_…), at most 50. |
Response
200 OK with the new role IDs.
{
"role_ids": [
"rol_01j9xr7s1t2w6x8y0z2a4b6c8e"
]
}
Errors
| HTTP | code | When |
|---|---|---|
| 403 | role_not_assignable |
A role is an organization role. |
| 404 | not_found |
The user does not exist in this environment. |
| 422 | validation_failed |
role_ids is missing, has a malformed or unknown ID (unknown_role), a duplicate or more than 50 items. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. Assigning a privileged (is_privileged) role also requires roles:write; without it nothing is written and required_permissions lists both permissions. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry after the Retry-After period. |
Example
curl -i -X PUT "https://api.eu.keenauth.com/v1/users/usr_01j9xh2k6p7q1r3s5t7v9w1x3y/roles" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"role_ids":["rol_01j9xr7s1t2w6x8y0z2a4b6c8e"]}'