Keycloak JWT to contain user real and client role - jwt

I'm using Keycloak version 20.0.1 (also tried on 19.0.0).
I have a realm configured and under the Client Scopes -> realm roles -> Mappers I have added the realm_access.roles mapping.
For some reasons that I don't understand, the JWT token that I get as a response doesn't contain the Realm Roles (I have also assigned a realm role to the user that it's used for testing).
The response that I get is:
{
"exp": 1669579902,
"iat": 1669579602,
"auth_time": 1669577841,
"jti": "9dfe2638-a9f8-4094-8691-7a1423b629f7",
"iss": "https://auth.xxxx.com/realms/xxxx.com",
"sub": "6fe1b9b9-5ddd-478d-9b38-bd11698295cf",
"typ": "Bearer",
"azp": "spring-client",
"nonce": "d14b168b-3c77-489b-85dd-192dba533624",
"session_state": "55d938d4-42e7-4c2b-9038-f808c917c366",
"acr": "0",
"allowed-origins": [
"*"
],
"scope": "openid email profile roles",
"sid": "55d938d4-42e7-4c2b-9038-f808c917c366",
"email_verified": true,
"name": "first last",
"preferred_username": "user#email.com",
"given_name": "first",
"family_name": "last",
"email": "user#email.com"
}
How should I add the roles into the JWT response returned by Keycloak?
I have tried to configure the Client Scopes -> ream roles -> Mappers and I was expecting to receive in the JWT response the roles field.

In the JWT of Keycloak, two roles information.
It is not represented user's assigned role. Just assigned client role are included but realm's roles is possible list of realm.
If you want to get all of assigned role, have to call role mapping of user API (see #3.1)
I decoded JWT by jwo.io after get access token by Postman with Keycloak v 19.0.2
#1 realm roles list - It is not assigned realm role list, it is possible role list
User JWT(access token), get grant_type = password
{
"exp": 1669599866,
"iat": 1669596266,
"jti": "ad4e3b51-b23e-4abb-aba6-0099bb5213cf",
"iss": "http://localhost:8080/auth/realms/example",
"aud": "account",
"sub": "fae8bf9b-2209-4f01-ab32-629e029941ba",
"typ": "Bearer",
"azp": "spring-client",
"session_state": "8debdcfa-4252-4a27-8190-2a4981e6a795",
"acr": "1",
"realm_access": {
"roles": [
"offline_access",
"admin",
"default-roles-example",
"uma_authorization",
"user"
]
},
"resource_access": {
"spring-client": {
"roles": [
"client role2"
]
}
},
"scope": "openid profile email",
"sid": "8debdcfa-4252-4a27-8190-2a4981e6a795",
"email_verified": false,
"name": "first last",
"preferred_username": "user",
"given_name": "first",
"family_name": "last",
"email": "user#test.com"
}
five realm's roles are possible realm's role not assigned user's roles
User just assigned three realm's roles
Client JWT(access token), get grant_type = client_credentials
{
"exp": 1669597154,
"iat": 1669593554,
"jti": "ff6ae9db-7e05-4f9a-a538-0755a7f55125",
"iss": "http://localhost:8080/auth/realms/example",
"aud": "account",
"sub": "9db11aa2-6862-4ebb-9ee6-b03b51d7814d",
"typ": "Bearer",
"azp": "spring-client",
"acr": "1",
"realm_access": {
"roles": [
"offline_access",
"default-roles-example",
"uma_authorization"
]
},
"scope": "openid profile email",
"clientId": "spring-client",
"clientHost": "172.19.0.1",
"email_verified": false,
"preferred_username": "service-account-spring-client",
"clientAddress": "172.19.0.1"
}
Those are client's roles, it has three roles but not matched JWT's realm list
In the JWT (client access token), that list is possible realm list(not assigned client realm roles)
#2 client role - It is assigned client list
GET {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/clients/{client-UUID}/roles
http://localhost:8080/auth/admin/realms/example/clients/1cb76d56-b96f-42a7-91c0-c201a7761e9e/roles
[
{
"id": "e5171eb5-976e-429f-914c-0d63d7b394fd",
"name": "client role2",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
},
{
"id": "293c9c9c-bb76-4192-be09-ede769458394",
"name": "uma_protection",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
},
{
"id": "e1441ceb-7ea8-436b-9a55-30999c6de744",
"name": "client role1",
"description": "",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
}
]
#3 user's role list can get the separate API
3.1 all of user's role
GET {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/users/{USER-UUID}/role-mappings
UI:
It seems to block, UI not allow to assign directly a user into client role from UI. I use REST API call. Here
Example, get user's roles:
http://localhost:8080/auth/admin/realms/example/users/fae8bf9b-2209-4f01-ab32-629e029941ba/role-mappings
Response
{
"realmMappings": [
{
"id": "c31bd5ce-e400-4546-b633-d4d5bde596d8",
"name": "admin",
"description": "Administrator privileges",
"composite": false,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
},
{
"id": "d99f61be-bacd-438d-974d-06a006704a1e",
"name": "default-roles-example",
"description": "${role_default-roles}",
"composite": true,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
},
{
"id": "8d250d6c-e249-4b63-b86f-390b4550b12e",
"name": "user",
"description": "User privileges",
"composite": false,
"clientRole": false,
"containerId": "e78f0c77-b44b-48da-850b-9d157e24a439"
}
],
"clientMappings": {
"spring-client": {
"id": "1cb76d56-b96f-42a7-91c0-c201a7761e9e",
"client": "spring-client",
"mappings": [
{
"id": "e5171eb5-976e-429f-914c-0d63d7b394fd",
"name": "client role2",
"composite": false,
"clientRole": true,
"containerId": "1cb76d56-b96f-42a7-91c0-c201a7761e9e"
}
]
}
}
}
If you want to see, how to set the role into client or user,here

to get roles or anything in token we had protocol mappers in version 18.0 and earlier. for version 19 and above it is removed but only from ui
you can add protocol mapper by rest api
/POST {keycloak_url}/admin/realms/demo/clients/<clientId>/protocol-mappers/models
authorization:Bearer token //should be admin token
{
"protocol":"openid-connect",
"config{
"multivalued":"true",
"id.token.claim":"true",
"access.token.claim":"true",
"userinfo.token.claim":"true",
"usermodel.realmRoleMapping.rolePrefix":"",
"claim.name":"realmRoles"
},
"name":"roleNameMapper",
"protocolMapper":"oidc-usermodel-realm-role-mapper"
}

Related

Getting first name, last name and email from Keycloak using Quarkus OIDC integration

When I access the /openid-connect/token endpoint using admin_cli client_id I can see more/different info in the payload of returned access_token compared to when token is injected into my bean by the Quarkus OIDC/Keycloak extension.
Here are some samples:
{
"exp": 1671084133,
"iat": 1671083533,
"jti": "b95bac0a-f95e-413d-b2cd-3b97fcf5f3c8",
"iss": "http://localhost:51521/realms/my-realm",
"sub": "cda64011-47a8-4a6a-8aac-06c7db6fc593",
"typ": "Bearer",
"azp": "admin-cli",
"session_state": "be12a28b-4143-4bbf-9914-c8454d93f50f",
"acr": "1",
"scope": "profile email",
"sid": "be12a28b-4143-4bbf-9914-c8454d93f50f",
"email_verified": false,
"preferred_username": "test",
"given_name": "vasia",
"family_name": "pupkin",
"email": "test#test.com"
}
Versus
{
"exp": 1671086253,
"iat": 1671085653,
"auth_time": 1671085653,
"jti": "05e9f66d-54a1-440b-9295-3ebd681a853a",
"iss": "http://localhost:51521/realms/my-realm",
"sub": "cda64011-47a8-4a6a-8aac-06c7db6fc593",
"typ": "Bearer",
"azp": "my-app",
"session_state": "ba00821c-1556-4214-90d7-5f2a55b0074a",
"scope": "openid microprofile-jwt",
"sid": "ba00821c-1556-4214-90d7-5f2a55b0074a",
"upn": "test",
"groups": [
"offline_access",
"admin",
"uma_authorization",
"default-roles-collar-club"
]
}
I'm interested in still getting the groups (for role based access) and given_name, family_name, email properties as well in my Quarkus app.
Tried to specify: quarkus.oidc.authentication.scopes=openid,profile,groups - getting error in the url redirected from Keycloak:
2022-12-14 23:11:19,984 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-2) Authentication has failed, error: invalid_scope, description: Invalid scopes: openid openid profile groups
openid is always added by Quarkus, Keycloak does not like duplicate scope values, so remove openid

Problem in assigning roles to user while creating it with Post HTTP request

I can successfully create user by calling the following path in Postman software:
http://{KEYCLOAK_IP}/auth/admin/realms/{REALM_NAME}/users
The body content that I send is like following:
{
"enabled":true,
"username":"Reza",
"email":"reza#sampleMailServer1.com",
"firstName":"Reza",
"lastName":"Azad",
"credentials": [
{
"type":"password",
"value":"123",
"temporary":false
}
]
}
Now, let’s assume that we have a client, which is named browserApp and this client has a role, which is named borwserAppRoleUser. Also, the realm has a role, which is name realmRoleUser.
In order to include abovementioned roles in the body content of the HTTP request I tried the following structure:
{
"enabled":true,
"username":"Reza",
"email":"reza#sampleMailServer1.com",
"firstName":"Reza",
"lastName":"Azad",
"credentials": [
{
"type":"password",
"value":"123",
"temporary":false
}
],
"role": [
{
"id": "borwserAppRoleUser",
"name": "test",
"description": "${role_create-client}",
"composite": false,
"clientRole": true,
"containerId": "browserApp"
},
{
"id":"realmRoleUser",
"composite":false,
"clientRole":false
}
]
}
Sending the above body content results in 400 bad request response. The errors contains this message:
Unrecognized field "role" (class org.keycloak.representations.idm.UserRepresentation), not marked as ignorable
Also, I am sure that the rest of the role object is not correct.
I searched for examples online, but I could not find any sample regarding the role assignment. Can any body please help me to fix this problem?
REST API not supports realm & client roles by single JSON data.
It only support by Add Realm with JSON import
The simple JSON format is like this but it needs extra data.
This is working example for Import Realm JSON data
{
"id": "test",
"realm": "test",
"users": [
{
"enabled": true,
"username": "Reza",
"email": "reza#sampleMailServer1.com",
"firstName": "Reza",
"lastName": "Azad",
"credentials": [
{
"type": "password",
"value": "123",
"temporary": false
}
],
"realmRoles": [
"user"
],
"clientRoles": {
"borwserAppRoleUser": [
"test"
]
}
}
],
"scopeMappings": [
{
"client": "borwserAppRoleUser",
"roles": [
"test"
]
}
],
"client": {
"borwserAppRoleUser": [
{
"name": "test",
"description": "${role_create-client}"
}
]
},
"roles": {
"realm": [
{
"name": "user",
"description": "Have User privileges"
}
]
}
}
If you want to assign user's realm role and client role, use separate API call.
#1 Assign user's realm role
POST {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/users/{USER-UUID}/role-mappings/realm
In Body of POST
[
{
"id": {REALM ROLE UUID},
"name": {ROLE NAME},
"composite": false,
"clientRole": false,
"containerId": {REALM NAME}
}
]
1.1 Get master token - here
1.2 Get User UUID
1.3 Get Realm role UUID and name
1.4 POST realm role into user
#2 Assign user's client role
POST {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/users/{USER-UUID}/role-mappings/clients/{CLIENT-UUID}
In Body of POST
[
{
"id": {CLIENT ROLE ID},
"name": {ROLE NAME},
"description": "${role_create-client}",
"composite": false,
"clientRole": true,
"containerId": {CLIENT-UUID}
}
]
2.1 Get master token
2.2 Get user UUID - same 1.2
2.2 Get Client UUID
2.3 Get Client role UUID & name
2.4 POST client role into user
Finally confirm both assigned roles by this API
GET {KEYCLOAK-IP}/auth/admin/realms/{REALM-NAME}/users/{USER-UUID}/role-mappings

How to get the roles in Auth0's user management to be added in the JWT?

I have an Auth0 application and I'm maintaining roles through the User Management. I would like to get those roles that are assigned to a user to be added to the JWT returned.
I do have the following in the openid_connect_configuration.conf
map $host $oidc_scopes {
default "openid+profile+email+offline_access+openid roles";
}
i have the following in the /.well-known/openid-configuration
{
...
"scopes_supported": [
"openid",
"profile",
"offline_access",
"name",
"given_name",
"family_name",
"nickname",
"email",
"email_verified",
"picture",
"created_at",
"identities",
"phone",
"address"
],
"response_types_supported": [
"code",
"token",
"id_token",
"code token",
"code id_token",
"token id_token",
"code token id_token"
],
"code_challenge_methods_supported": [
"S256",
"plain"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": [
"HS256",
"RS256"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"claims_supported": [
"aud",
"auth_time",
"created_at",
"email",
"email_verified",
"exp",
"family_name",
"given_name",
"iat",
"identities",
"iss",
"name",
"nickname",
"phone_number",
"picture",
"sub"
],
"request_uri_parameter_supported": false
}
How do I set things in Auth0 to return the roles assigned to the logged in user? I have tried looking into the documentation, but I had no luck.
I found my answer through exploring the extensions in Auth0. I installed the Auth0 Authorization extension. I enabled the groups and roles.
I then added the following rule:
function setRolesToUser(user, context, callback) {
// Roles should only be set to verified users.
if (!user.email || !user.email_verified) {
return callback(null, user, context);
}
user.app_metadata = user.app_metadata || {};
auth0.users
.updateAppMetadata(user.user_id, user.app_metadata)
.then(function () {
context.idToken['https://example.com/auth'] = user.app_metadata.authorization;
callback(null, user, context);
})
.catch(function (err) {
callback(err);
});
}
I get the following as the JWT payload:
{
"https://example.com/auth": {
"groups": ["Samples"],
"roles": ["Editor"]
},
"sub": "auth0|xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"nickname": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email_verified": true,
"iss": "https://dev-xxxxxxxxxx.us.auth0.com/",
"updated_at": "2022-04-29T20:01:14.585Z",
"iat": 1.651330616E9,
"picture": "https://s.gravatar.com/avatar/a705adb3d5d8530c35c41a9de260cd3c?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Flo.png",
"exp": 1.651366616E9,
"name": "xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx",
"aud": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"nonce": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email": "xxxxx.xxxxxxxxx#example.com"
}

Keycloak: Access token client-1 to manage client-2 resources

I have two clients in Keycloak:
CP: Client public
CC: Client confidential with Service Accounts enabled and several resources.
Resources owners are users who created them and they manage the access too.
The User (U) who created the Resource (R) can log in to CC and use the access token for call endpoints on CP.
Now I would like U will be able to set UMA policies, but the access token is from CP, not from CC where the resources are, so Keycloak is complaining about de token.
org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 403 / Forbidden / Response from server: {\"error\":\"invalid_clientId\",\"error_description\":\"Client application [CP] is not registered as a resource server.\"}
fun onlyOwner(accessToken: String, id: String, resourceId: String) {
val request = UmaPermissionRepresentation()
request.name = "Only owner can view $id"
request.description = "Only owner can view this resource"
request.scopes = setOf(ResourceScope.VIEW)
request.condition = ONLY_OWNER_CONDITION
authzClient.protection(accessToken).policy(resourceId).create(request)
}
Keycloak docs mention the following:
"
The Policy API is available at:
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id} This API is protected by a bearer token that must represent a consent granted by the user to the resource server to manage permissions on his behalf. The bearer token can be a regular access token obtained from the token endpoint using:
Resource Owner Password Credentials Grant Type
Token Exchange, in order to exchange an access token granted to some client (public client) for a token where audience is the resource server
I exchanged the CP client to CC client:
Original token:
{
"exp": 1606687405,
"iat": 1606651407,
"auth_time": 1606651405,
"jti": "1e4075a9-ce49-4462-91f7-33b8963f56dd",
"iss": "http://localhost/auth/realms/test",
"aud": "account",
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"*"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
Exchanged token:
{
"exp": 1606687405,
"iat": 1606652039,
"auth_time": 1606651405,
"jti": "0c84f42a-973e-4bc7-9a6d-2c4fec548512",
"iss": "http://localhost/auth/realms/test",
"aud": [
"account",
"CC"
],
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"http://localhost"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
But the error persists alghout aud changed from account to [account,cc].
The solution is exchanging the token using as client_id and client_secret the target client (cc). After that, you can use the access_token returned by Keycloak as bearer token for creating the UMA_Policy.
Exchange public client token to the confidential client token
Create a policy with the new access token

Keycloak : unable to map user roles when creating user for api

I am new to Keycloak. I want create user using Keycloak admin REST API.
I have managed to create a user. But the problem is I also want to assign admin role to the user.
Attached is my JSON body. Can someone tell me what am I doing wrong here?
{
"username": "username",
"email": "user#gmail.com",
"firstName": "name1",
"lastName": "name2",
"realmRoles": [ "admin" ],
"enabled": true,
"credentials": [{
"type": "password",
"value": "default",
"temporary": false
}]
}
Thank you in advance