curl --request PUT \
--url https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"roles": []
}'import requests
url = "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}"
payload = { "roles": [] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({roles: []})
};
fetch('https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'roles' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}"
payload := strings.NewReader("{\n \"roles\": []\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"roles\": []\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"roles\": []\n}"
response = http.request(request)
puts response.read_body{
"workspace": "<string>",
"role_grants": [
{
"keycloak_role": "<string>",
"roles": [
"workspace_admin"
],
"granted_by": "<string>",
"granted_at": "2023-11-07T05:31:56Z"
}
],
"members": [
{
"subject": "<string>",
"roles": [
"workspace_admin"
],
"granted_by": "<string>",
"granted_at": "2023-11-07T05:31:56Z"
}
]
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}Grant workspace roles to a Keycloak role
Replace the workspace roles held by everyone with a Keycloak role.
The submitted list is the complete set. Granting checks that the role exists in the realm: an unknown role returns 422, and 503 means Keycloak couldn’t be reached to check it. Nothing is granted in either case. Send an empty list to revoke. Revoking doesn’t contact Keycloak, so you can remove grants for a role that has since been deleted. Requires a Keycloak session; PSK credentials can’t change who has access.
Required roles: workspace_admin or nx1_decisions_admin
curl --request PUT \
--url https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"roles": []
}'import requests
url = "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}"
payload = { "roles": [] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({roles: []})
};
fetch('https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'roles' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}"
payload := strings.NewReader("{\n \"roles\": []\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"roles\": []\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/decisions/{workspace}/role-grants/{keycloak_role}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"roles\": []\n}"
response = http.request(request)
puts response.read_body{
"workspace": "<string>",
"role_grants": [
{
"keycloak_role": "<string>",
"roles": [
"workspace_admin"
],
"granted_by": "<string>",
"granted_at": "2023-11-07T05:31:56Z"
}
],
"members": [
{
"subject": "<string>",
"roles": [
"workspace_admin"
],
"granted_by": "<string>",
"granted_at": "2023-11-07T05:31:56Z"
}
]
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Path Parameters
Workspace slug.
64^[a-z0-9][a-z0-9-]{0,63}$Keycloak realm role name. URL-encode it.
1 - 255Body
Complete set of workspace roles for this grantee. Replaces any existing grants — send an empty list to revoke.
Per-workspace role grants.
workspace_admin deliberately cannot approve: separation of duties
is the point of the matrix, and approval requires a distinct
approver identity.
workspace_admin, author, approver, simulator, viewer Response
Successful Response
Workspace roles granted to Keycloak roles. This is how access is granted.
Show child attributes
Show child attributes
Legacy grants made directly to users. Still honoured and revocable, but no new ones can be made — replace them with role grants.
Show child attributes
Show child attributes
Was this page helpful?

