Keycloak - 401 response (USER_INFO_REQUEST_ERROR) when obtaining userinfo via /realms/{realm}/protocol/openid-connect/userinfo - keycloak

I have a Keycloak deployed locally with the following Docker command:
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e
KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:20.0.1
start-dev
I get a token from Keycloak. Example:
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMZjRfWHJjWkpTaVJYWlFLS254VS1NdU9FTHA4d3NaaHlLMDQ0UjRIRjdnIn0.eyJleHAiOjE2NzAwODc1MDgsImlhdCI6MTY3MDA4NzIwOCwiYXV0aF90aW1lIjoxNjcwMDg2NDcwLCJqdGkiOiIyYWQxODQ5ZC0xMjI0LTQ4YjYtYWZjYy01ZmFjMWZjODY3ZjQiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL2RpYWxvZy1mZWF0IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRkYjdiNjg1LTRkYTAtNGZjMy1iNjI1LTgyZmM1MTdjNjA3NiIsInR5cCI6IkJlYXJlciIsImF6cCI6InNvbWV4NSIsIm5vbmNlIjoiR0tNb1JWRTVDajZSVjJMcFQ1Mjg5eVQ3RUdWeFMzZk4iLCJzZXNzaW9uX3N0YXRlIjoiMTY4Y2JmZGQtMmFmYS00Mjk5LWI4YmUtMmExM2FjMjI2NzJiIiwiYWNyIjoiMCIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiZGVmYXVsdC1yb2xlcy1kaWFsb2ctZmVhdCJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJzaWQiOiIxNjhjYmZkZC0yYWZhLTQyOTktYjhiZS0yYTEzYWMyMjY3MmIiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IkpvaG4gU25vdyIsInByZWZlcnJlZF91c2VybmFtZSI6ImpvaG4uc25vdyIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJTbm93IiwiZW1haWwiOiJqb2huLnNub3dAeDUucnUifQ.j_rFqVxICtj7NR-myEsWhSkwBeCABplFrmlBuRMAhF4N8HzdOOtExdmw_mXdx60snKTaE5GJHPofjllpM353lY8H9NGxaczUgL20GjVmMhwtihGGBLpiw7TXyGQGkfdBXdweCuS0W1avegXrhRYvCYlFGJMoxsdmskYkDt4DjuESlTkMEOndVjv5LBp3rLB6lRopq0Qg3Abp_rv57KvlVeeul24OKoisFohnZ4VfsiDPAuVW1u1xaYmjCRDlBwIcGosdwasL_WNAgvJkaKdVtvu7NU-ghPa1vQkWJkMZrVIZDsCc5LKZqwspw3U2iOcUc5EDC6FumBWdfvWCx8cszw
Its payload:
{
"exp": 1670087508,
"iat": 1670087208,
"auth_time": 1670086470,
"jti": "2ad1849d-1224-48b6-afcc-5fac1fc867f4",
"iss": "http://localhost:8080/realms/dialog-feat",
"aud": "account",
"sub": "4db7b685-4da0-4fc3-b625-82fc517c6076",
"typ": "Bearer",
"azp": "somex5",
"nonce": "GKMoRVE5Cj6RV2LpT5289yT7EGVxS3fN",
"session_state": "168cbfdd-2afa-4299-b8be-2a13ac22672b",
"acr": "0",
"realm_access": {
"roles": [
"offline_access",
"uma_authorization",
"default-roles-dialog-feat"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"sid": "168cbfdd-2afa-4299-b8be-2a13ac22672b",
"email_verified": true,
"name": "John Snow",
"preferred_username": "john.snow",
"given_name": "John",
"family_name": "Snow",
"email": "john.snow#x5.ru"
}
It seems valid. Then I'm making a request to http://127.0.0.1:8080/realms/dialog-feat/protocol/openid-connect/userinfo with the token:
curl --location --request GET
'http://127.0.0.1:8080/realms/dialog-feat/protocol/openid-connect/userinfo'
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMZjRfWHJjWkpTaVJYWlFLS254VS1NdU9FTHA4d3NaaHlLMDQ0UjRIRjdnIn0.eyJleHAiOjE2NzAwODc1MDgsImlhdCI6MTY3MDA4NzIwOCwiYXV0aF90aW1lIjoxNjcwMDg2NDcwLCJqdGkiOiIyYWQxODQ5ZC0xMjI0LTQ4YjYtYWZjYy01ZmFjMWZjODY3ZjQiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL2RpYWxvZy1mZWF0IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRkYjdiNjg1LTRkYTAtNGZjMy1iNjI1LTgyZmM1MTdjNjA3NiIsInR5cCI6IkJlYXJlciIsImF6cCI6InNvbWV4NSIsIm5vbmNlIjoiR0tNb1JWRTVDajZSVjJMcFQ1Mjg5eVQ3RUdWeFMzZk4iLCJzZXNzaW9uX3N0YXRlIjoiMTY4Y2JmZGQtMmFmYS00Mjk5LWI4YmUtMmExM2FjMjI2NzJiIiwiYWNyIjoiMCIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiZGVmYXVsdC1yb2xlcy1kaWFsb2ctZmVhdCJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJzaWQiOiIxNjhjYmZkZC0yYWZhLTQyOTktYjhiZS0yYTEzYWMyMjY3MmIiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IkpvaG4gU25vdyIsInByZWZlcnJlZF91c2VybmFtZSI6ImpvaG4uc25vdyIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJTbm93IiwiZW1haWwiOiJqb2huLnNub3dAeDUucnUifQ.j_rFqVxICtj7NR-myEsWhSkwBeCABplFrmlBuRMAhF4N8HzdOOtExdmw_mXdx60snKTaE5GJHPofjllpM353lY8H9NGxaczUgL20GjVmMhwtihGGBLpiw7TXyGQGkfdBXdweCuS0W1avegXrhRYvCYlFGJMoxsdmskYkDt4DjuESlTkMEOndVjv5LBp3rLB6lRopq0Qg3Abp_rv57KvlVeeul24OKoisFohnZ4VfsiDPAuVW1u1xaYmjCRDlBwIcGosdwasL_WNAgvJkaKdVtvu7NU-ghPa1vQkWJkMZrVIZDsCc5LKZqwspw3U2iOcUc5EDC6FumBWdfvWCx8cszw'
But I get a 401 status code returned. For example:
type=USER_INFO_REQUEST_ERROR, realmId=(...), clientId=null, userId=null, ipAddress=(...), error=access_denied, auth_method=validate_access_token
How to fix this?
My Keycloak settings:

The problem seems to be a mismatch between the issuer of the access token sent to the userinfo endpoint (i.e., "iss": "http://localhost:8080/realms/dialog-feat") and the issuer that the access token validator triggered by the userinfo endpoint is expecting.
Instead of:
Then I'm making a request to
http://127.0.0.1:8080/realms/dialog-feat/protocol/openid-connect/userinfo
with the token (...):
Use the same hostname in the userinfo endpoint has the one that you have used to acquire the access token, for instance:
curl http://localhost:8080/realms/dialog-feat/protocol/openid-connect/userinfo -H "Authorization: Bearer (..<your access token..)"
If the problem still persistes then you also facing the issues related with the Keycloak endpoint implementation described in UserInfo endpoint not fully standards compliant.
In short in your request for a the access token explicitly add the parameter scope=openid. An example:
curl --request POST \
--url "http://localhost:8080/realms/dialog-feat/protocol/openid-connect/token" \
--data client_id=somex5 \
--data username=john.snow \
--data password=...<the password..> \
--data grant_type=password \
--data scope=openid

Related

How can i create user with multiple Client roles in a single API

I want to create a user and assign a client role with it in a single API in Keycloak I have attached the details.
I have this API
http://testkeycloak.com:8085/auth/admin/realms/engineer/users
{
"enabled":true,
"username":"joshbiden",
"email":"email#gmail.com",
"firstName":"Josh",
"lastName":"biden",
"attributes":
{
"Mobile Number":"3333332332"
},
"clientRoles":
{
"name": "DEVELOPER"
},
"credentials":
[
{
"type":"password",
"value":"rollback",
"temporary":false
}
]
}
CLIENT ROLE - DETAILS
{
"id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
"name": "DEVELOPER",
"composite": false,
"clientRole": true,
"containerId": "343434-7631-4187-ac76-ad78de119b90"
}
How can I assign two clients' roles to the USER, I have tried to add users but facing an unknown error. Let me know any solution for the same
I want to create a user and assign a client role with it in a single
API in Keycloak I have attached the details.
Unfortunately, it is impossible to do that with a single API call, even though the Keycloak Admin rest API documentation infers otherwise. This can be confirmed by looking at this GitHub issue. Quoting the reply from that thread (from the Keycloak Project Leader Stian Thorgersen):
So, unfortunately, the answer from #Devendra Mahajan is simply not correct.
The solution is to perform two calls, namely:
one to create the user
another to assign the roles
First create the user using the endpoint POST /{realm}/users and with the following data (without the role):
{
"username": "joshbiden",
"enabled": true,
"firstName": "Josh",
"lastName": "biden",
"email": "email#gmail.com",
"attributes": {
"Mobile Number": [
"3333332332"
]
},
"credentials": [{
"type":"password",
"value":"rollback",
"temporary":false
}]
}
Second, you assign the role using the endpoint :
POST /{realm}/users/{id}/role-mappings/clients/{id of client}
with the data:
[{
"id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
"name": "DEVELOPER",
"composite": false,
"clientRole": true,
"containerId": "343434-7631-4187-ac76-ad78de119b90"
}]
Step-by-Step
Warning: The /auth path was removed starting with Keycloak 17 Quarkus distribution. So you might need to remove the /auth from the endpoint calls presented on this answer.
To use Keycloak Admin REST API you need an access token from a user with the proper permissions. I will be using the admin user from the master realm:
curl "https://${KEYCLOAK_HOST}/auth/realms/master/protocol/openid-connect/token" \
-d "client_id=admin-cli" \
-d "username=$ADMIN_NAME" \
-d "password=$ADMIN_PASSWORD" \
-d "grant_type=password"
You will get a JSON with the admin's token. Extract the value of property access_token from that response. Let us save it in the variable $ACCESS_TOKEN for later reference.
To create the user in your realm $REALM_NAME:
curl -X POST "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users"
-H "Content-Type: application/json" \
-H "Authorization: bearer $ACCESS_TOKEN" \
-d "${USER_JSON_DATA}"
For those that need you can also have a look at my scripts to automatize the user creation on GitHub, namely this or this.
To assign the client role to the user you need the know beforehand the following fields:
id of the user
id of the client
client role representation
To get the user id from your realm $REALM_NAME:
curl -X GET "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/?username=${USERNAME}" \
-H "Content-Type: application/json" \
-H "Authorization: bearer $ACCESS_TOKEN"
From the response extract the user id for example as follows
jq -r ".[] | select(.username==\"$USERNAME\")" | jq -r id
and save it in the variable ${USER_ID}.
To get the client id call the endpoint get clients with the parameter clientID:
curl -X GET "${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_ID}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Extract id from the response (e.g., jq -r .[0].id) and save it in variable ${ID_OF_CLIENT}.
With the previous id you can get the client role as follows:
curl -X GET "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients/${ID_OF_CLIENT}/roles/${ROLE_NAME}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Save the json response in ${CLIENT_ROLE}, and assign the role to the user as follows:
curl -X POST "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${ID_OF_CLIENT}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d "${CLIENT_ROLE}"
I have created scripts for the aforementioned steps that can be accessed here and executed using the script getClientRoleByName.sh.
Try This,
{
"enabled": true,
"username": "joshbiden",
"email": "email#gmail.com",
"firstName": "Josh",
"lastName": "biden",
"attributes": {
"Mobile Number": "3333332332"
},
"clientRoles": {
"<name-of-the-client-in-realm>": ["DEVELOPER"]
},
"credentials": [
{
"type": "password",
"value": "rollback",
"temporary": false
}
]
}
This can be achieved using the partial import API
POST /{realm}/partialImport
With this API you can also import multiple users in one call.
This is not a solution for update though.
Body sample:
{
"users": [
{
"username": "user1",
"enabled": true,
"totp": false,
"emailVerified": true,
"firstName": "First name",
"lastName": "Last name",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": true,
"manage": true
},
"groups": [
],
"realmRoles": [
]
},
{
"username": "user2",
"enabled": true,
"totp": false,
"emailVerified": true,
"firstName": "User 2",
"lastName": "Last name",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": true,
"manage": true
},
"groups": [
],
"realmRoles": [
"some realm role"
],
"clientRoles": {
"some client": [
"some client role"
]
}
}
]
}

Keycloak Update / Delete client after dynamic client registration

In Keycloak dynamic client registration works fine:
curl --request POST \
--url http://localhost:8080/auth/realms/myrealm/clients-registrations/default \
--header 'content-type: application/json' \
--data '{"clientId": "myclient"}'
As a response I receive the client representation with especially the registrationAccessToken:
{
"id": "4c6c36d0-6a53-41d9-be37-46bd0d67ebd2",
"clientId": "myclient",
"surrogateAuthRequired": false,
"enabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "1f85aa4e-6cdc-4f6c-83ba-f3c67d4561f2",
"registrationAccessToken": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2YWIyYTVjZC0xNjgwLTQ5MTYtYmUzYi0wZmFmMjVmZDczMzQifQ.eyJqdGkiOiI3YjVlMjE5Ny0yZjA5LTQwNTgtYmU0ZC02MDM1M2QzMGFkNWIiLCJleHAiOjAsIm5iZiI6MCwiaWF0IjoxNTg0NTQxNTY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvOTQ5IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zLzk0OSIsInR5cCI6IlJlZ2lzdHJhdGlvbkFjY2Vzc1Rva2VuIiwicmVnaXN0cmF0aW9uX2F1dGgiOiJhbm9ueW1vdXMifQ.NCqZ6yJrKz9t3vs65kwM88PNvsZMmxig3vqOmc_iLyE",
"redirectUris": [],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": false,
"frontchannelLogout": false,
"protocol": "openid-connect",
"attributes": {},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"web-origins",
"role_list",
"profile",
"roles",
"email"
],
"optionalClientScopes": [
"address",
"phone",
"offline_access",
"microprofile-jwt"
]
}
According the documentation one should be able to read, update and delete the client with the registrationAccessToken:
It will return a Client Representation that also includes the registration access token. You should save the registration access token somewhere if you want to retrieve the config, update or delete the client later.
However, when trying to read the just created client, I receive a 401 Unothorized when using the registrationAccessToken received from registration.
curl --request GET \
--url http://localhost:8080/auth/realms/myrealm/clients-registrations/default/4c6c36d0-6a53-41d9-be37-46bd0d67ebd2 \
--header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2YWIyYTVjZC0xNjgwLTQ5MTYtYmUzYi0wZmFmMjVmZDczMzQifQ.eyJqdGkiOiI3YjVlMjE5Ny0yZjA5LTQwNTgtYmU0ZC02MDM1M2QzMGFkNWIiLCJleHAiOjAsIm5iZiI6MCwiaWF0IjoxNTg0NTQxNTY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvOTQ5IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zLzk0OSIsInR5cCI6IlJlZ2lzdHJhdGlvbkFjY2Vzc1Rva2VuIiwicmVnaXN0cmF0aW9uX2F1dGgiOiJhbm9ueW1vdXMifQ.NCqZ6yJrKz9t3vs65kwM88PNvsZMmxig3vqOmc_iLyE'
< HTTP/1.1 401 Unauthorized
{
"error": "invalid_token",
"error_description": "Not authorized to view client. Not valid token or client credentials provided."
}
Any idea what I am missing?
Try changing from:
--url http://localhost:8080/auth/realms/myrealm/clients-registrations/default/4c6c36d0-6a53-41d9-be37-46bd0d67ebd2 \
to:
--url http://localhost:8080/auth/realms/myrealm/clients-registrations/default/myclient \

add claims to access token keycloak

Below is my use case:
I need to add a claim to the access token so that i can use it during policy evaluation on my resource. My policy is a javascript based policy and it gets access only to reserved and custom attributes of the logged in user.
I have used the below api to push claims:
curl -X POST \
http://localhost:8082/auth/realms/cms-non-prod/protocol/openid-connect/token \
-H 'Authorization: Bearer eyJhbGciOiJSXXXXXXXXXXXXXXXX' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Postman-Token: ac020c2b-9efb-4817-81ea-61895c8775a7' \
-d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&claim_token=ewoiaW5zdGl0dXRpb25JZCI6WyJEQ0IiXQp9& claim_token_format=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt&client_id=indra-bff \
&client_Secret=5760582d-74ff-496c-a6c2-2530ddde6408&audience=indra-bff'
It adds the claim but it adds in to authorization--> Permissions-->Resources. How do i read this if i have a JS based policy.
Any pointers on this will help.
Below is the token i get when i hit above url:
{
"jti": "4c00f1a4-8038-4c45-820d-23a9c9ab6d42",
"exp": 1580733917,
"nbf": 0,
"iat": 1580730317,
"iss": "http://localhost:8082/auth/realms/cms-non-prod",
"aud": "indra-bff",
"sub": "9ab2fc80-3a5c-426d-ae78-56de01d214df",
"typ": "Bearer",
"azp": "indra-bff",
"auth_time": 0,
"session_state": "2ab35757-d09d-4d52-946b-f519a1338abf",
"acr": "1",
"realm_access": {
"roles": [
"PR_DCB_RECON_ASSOCIATE",
"PR_YBL_RECON_ASSOCIATE",
"offline_access",
"uma_authorization",
"PR_DCB_RECON_MGR"
]
},
"resource_access": {
"indra-bff": {
"roles": [
"uma_protection"
]
},
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"authorization": {
"permissions": [
{
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "17fdf554-8643-4741-b9a4-13309e830b6f",
"rsname": "Default Resource"
},
{
"scopes": [
"DELETE",
"POST",
"GET",
"PUT",
"PATCH"
],
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "56cabb7c-76a1-4260-bd9f-d5494458c6bf",
"rsname": "adjustment"
},
{
"scopes": [
"DELETE",
"POST",
"GET",
"PUT",
"PATCH"
],
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "70297346-8010-4c1d-91b1-9bc22edd3061",
"rsname": "chargeback"
}
]
},
"scope": "profile email",
"institution": "UNKNOWN",
"email_verified": false,
"preferred_username": "siva",
"email": "siva#goniyo.com"
}
Thanks for your help.
Cheers,
This method if for the UI. In your realm, select your client. For that client, go the 'Mappers' option and then click on 'Create'. You can have the mapper type as 'User Attribute' and select the option(s) to add the attribute to ID token, access token and userinfo. The attribute added here should exist on the user.
Check if you can get from the resource
var permission = $evaluation.getPermission();
var resource = permission.getResource();
Claims in your claim token can be reached through the Permission handle.
Considering your claim_token contains the following information:
{
"institutionId":["DCB"]
}
You can use this Javascript in your policy to fetch the string value "DCB":
$evaluation.getPermission().getClaims()["institutionId"].toArray()[0]
Source: Keycloak JavaDocs: ResourcePermission

error while importing curl request in Postman

I am trying to test rest api as mentioned here from Postman. I followed this thread here and tried importing the curl request in Postman but it's failing with the following error:
Here is the complete curl command:
curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Content-Type: application/json" \
--request PATCH \
--data '[
{
"operation": "add",
"field": "/members/-",
"value": {"_ref" : "managed/user/scarter"}
}
]' \
"http://localhost:8080/openidm/managed/role/cedadaed-5774-4d65-b4a2-41d455ed524a"
{
"_id": "cedadaed-5774-4d65-b4a2-41d455ed524a",
"_rev": "2",
"name": "employee",
"description": "Role granted to workers on the company payroll"
}

Ride wasn't canceled

I experienced issue in Uber rides API. Basically what happened was that the ride cancel endpoint returned 204 success response, but ride wasn't canceled.
This was first request:
curl -XDELETE -H 'Authorization: Bearer xxx' \
-H 'Accept-Language: en_US' \
-H 'Content-Type: application/json' \
'https://sandbox-api.uber.com/v1.2/requests/45546b81-cea5-4406-bde6-b574796606b8'
After that I received webhooks with ride canceled status and receipt ready:
{"event_id": "fbba171c-11b9-4081-b473-51ca19c35ceb", "resource_href": "https://sandbox-api.uber.com/v1/requests/45546b81-cea5-4406-bde6-b574796606b8/receipt", "meta": {"status": "ready", "rider_id": "xxx", "user_id": "xxx", "resource_id": "45546b81-cea5-4406-bde6-b574796606b8"}, "event_type": "requests.receipt_ready", "event_time": 1512401098}
{"event_id": "30d9efaa-f8eb-40f8-a0bd-7bf91ea4f7e3", "resource_href": "https://sandbox-api.uber.com/v1/requests/45546b81-cea5-4406-bde6-b574796606b8", "meta": {"status": "rider_canceled", "rider_id": "xxx", "user_id": "xxx", "resource_id": "45546b81-cea5-4406-bde6-b574796606b8"}, "event_type": "requests.status_changed", "event_time": 1512401098}
But when I asked about status later, returned response said that the status of ride is accepted:
curl -H 'Authorization: Bearer xxx' \
-H 'Accept-Language: en_US' \
-H 'Content-Type: application/json' \
'https://sandbox-api.uber.com/v1.2/requests/45546b81-cea5-4406-bde6-b574796606b8'
{"status":"accepted","product_id":"b8e5c464-5de2-4539-a35a-986d6e58f186","destination":{"latitude":40.783062,"eta":4,"longitude":-73.97125},"driver":{"phone_number":"(555)555-5555","rating":4.9,"picture_url":"https:\/\/d1a3f4spazzrp4.cloudfront.net\/uberex-sandbox\/images\/driver.jpg","name":"John","sms_number":null},"pickup":{"latitude":40.759068,"eta":1,"longitude":-73.98496},"request_id":"45546b81-cea5-4406-bde6-b574796606b8","location":{"latitude":40.75898,"bearing":null,"longitude":-73.98478},"vehicle":{"make":"Toyota","picture_url":"https:\/\/d1a3f4spazzrp4.cloudfront.net\/uberex-sandbox\/images\/prius.jpg","model":"Prius","license_plate":"UBER-PLATE"},"shared":false}
When I send cancel request again, it worked. What happened here?