Personal access tokens with Keycloak - keycloak

Is there way to create user-specific (aka. personal) access tokens in Keycloak?
So, our goal would be that a user creates one or more personal access tokens (like in GitHub or GitLab) and he/she uses these tokens for authentication.
Any idea how to achieve this using Keycloak?

Keycloak have no short size of personal API key
But you can use full size of JWT.
It is getting Access Token with password grant type.
This is demo
localhost:8180 – is a host and a port number on which the Keycloak server is running,
test – is a Keycloak Realm,
admin-cli – one of default client,
user: user name
1234: password
password : grand_type
The Grant Type is a way to exchange a user’s credentials for an access token.
$ curl -v -d "client_id=admin-cli" -d "username=user" -d "password=1234" -d "grant_type=password" -X POST "http://localhost:8180/auth/realms/test/protocol/openid-connect/token" | jq '.access_token'
result in terminal
"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6Q0hvYVhPX2hqbXFRTnNYOVlacnhkZmpUdk1sbWozUFNkSXpTWUJjMzRFIn0.eyJleHAiOjE2NjAzMzU4ODIsImlhdCI6MTY2MDMzNTU4MiwianRpIjoiYmFkMmFlNjktMWNiYS00NGMyLWEyZDctYzdhOWQ5YjQ4OGI4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MTgwL2F1dGgvcmVhbG1zL3Rlc3QiLCJzdWIiOiIzOTRiNjcwOS0zOGEyLTRhYTAtYTg0OS1mZTRjODFlNDA2MjQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoiZGM5YjI1YzEtOTRlMy00MTlhLTliOGQtMjYwZTVkMmY3MzcxIiwiYWNyIjoiMSIsInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6ImRjOWIyNWMxLTk0ZTMtNDE5YS05YjhkLTI2MGU1ZDJmNzM3MSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IlRvbSBDdXJpZXMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRvbSIsImZhbWlseV9uYW1lIjoiQ3VyaWVzIiwiZW1haWwiOiJ1c2VyQHRlc3QuY29tIn0.Gnx6WwpsUxQM990H89BBYi_Kiy3BdAQcCYFRknDJ9qpkGAZSYrAAjjEeEBA5ZXKIUzu0O2trly0iWVW1r4Lb5ihiqSva1BaR42v5WWXHL9gpeS-ttsoKP6N1x74msHXssRmjN5vZG_dwXF-gpKhhJmXI0fLW3-_uuH3LZ9Ar-4zNliVLjJGmePtzq74nn7WbwhggiWDQu2_mQFBnf9vJvcxn6jY9TX5oxppn4BNcvXrChAZyDXLt7RW32ud3p1Cs7Jn360Vg6cRo4wq7-Mams8hhnonhDEaakJtcin7gLK6jwFC7f2ND8banDYL3CEsem4HpmxSRX43UBhfyO64Z8A"
API call for getting user information with this access_token
$ curl --location --request GET 'http://localhost:8180/auth/realms/test/protocol/openid-connect/userinfo' --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6Q0hvYVhPX2hqbXFRTnNYOVlacnhkZmpUdk1sbWozUFNkSXpTWUJjMzRFIn0.eyJleHAiOjE2NjAzMzU4MjMsImlhdCI6MTY2MDMzNTUyMywianRpIjoiYjc3MjMzY2ItYTI2Zi00ZGNiLWJkZTktNjRiNzhiMmQzZTM2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MTgwL2F1dGgvcmVhbG1zL3Rlc3QiLCJzdWIiOiIzOTRiNjcwOS0zOGEyLTRhYTAtYTg0OS1mZTRjODFlNDA2MjQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoiNjg2Y2EyNDctMzZjYS00MTNiLWE4M2YtODUyZjJmNWY3YWVmIiwiYWNyIjoiMSIsInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6IjY4NmNhMjQ3LTM2Y2EtNDEzYi1hODNmLTg1MmYyZjVmN2FlZiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6IlRvbSBDdXJpZXMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ1c2VyIiwiZ2l2ZW5fbmFtZSI6IlRvbSIsImZhbWlseV9uYW1lIjoiQ3VyaWVzIiwiZW1haWwiOiJ1c2VyQHRlc3QuY29tIn0.KNioWAOTl7S5bYi303ZWkYRnTv4BnH9B7Q-Oe6j5nO5g_QD2RrWhMO1bUXA3uHdj5P3Y9Mk3vWYfsOlacVfYGmuYmGYhTD6LhbCILPf1r4qMBHUnAtPmWBUmLPNy1XQc-PPjVU6I0FzwW4-UoHCmrqgpDvSoarxf3PiUgwaYzPGm6IeAaHw-ndSO0vkhue2j2s8eVfiiH6TExkngq3zc8E1Y0WK3EM_LxcoDbfrRTNROYDqjK6Bi6_jIECjuRRC6E4ies1svMd8XGwS8iYuHB62hX7_rEBT4PmCwddjfE-IO6XoPy970gdWFUZfiRxbz1Orh-6SySVaeEPdskTGb2Q' | jq
result in terminal
{
"sub": "394b6709-38a2-4aa0-a849-fe4c81e40624",
"email_verified": false,
"name": "Tom Curies",
"preferred_username": "user",
"given_name": "Tom",
"family_name": "Curies",
"email": "user#test.com"
}
You can get the token end point by curl commend.
It is not necessary the access token.
curl --location --request GET 'http://localhost:8180/auth/realms/test/.well-known/openid-configuration' | jq
It will give a full list of result OIDC Discovery
{
"issuer": "http://localhost:8180/auth/realms/test",
"authorization_endpoint": "http://localhost:8180/auth/realms/test/protocol/openid-connect/auth",
"token_endpoint": "http://localhost:8180/auth/realms/test/protocol/openid-connect/token",
"introspection_endpoint": "http://localhost:8180/auth/realms/test/protocol/openid-connect/token/introspect",
"userinfo_endpoint": "http://localhost:8180/auth/realms/test/protocol/openid-connect/userinfo",
"end_session_endpoint": "http://localhost:8180/auth/realms/test/protocol/openid-connect/logout",
>>> deleted here next lines

I think you can customize the authentication flow using a custom Keycloak authentication SPI in that propagates passed personal token to the same 3-rd service that returns if the user is authenticated or not (see https://wjw465150.gitbooks.io/keycloak-documentation/content/server_development/topics/auth-spi.html for details)
Of course, you also need to create some web UI for token creation that will be then stored and verified with this custom SPI.

Related

How to get custom attributes for a user in Keycloak using the RESTful API?

I would assume this to be straight forward but I can't find it in the docs.
The following curl command:
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
'https://$URL/auth/realms/$REALM/protocol/openid-connect/userinfo'
results in:
{
"sub": "8182...415",
"email_verified": true,
"name": "n.a. n.a.",
"groups": [],
"preferred_username": "foo#example.com",
"given_name": "n.a.",
"family_name": "n.a.",
"email": "foo#example.com"
}
How do I get the custom attributes for a user?
You can get the user attributes with the get users endpoint from Admin Rest API:
GET /{realm}/users
with the query parameters, exact=true and username.
Step-by-Step:
You can get that information using the Keycloak Admin REST API; to call that API, you need an access token from a user with the proper permissions. For now, 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 response 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 get the user attributes from your realm $REALM_NAME:
curl -X GET https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/?username=${USERNAME}&exact=true \
-H "Content-Type: application/json" \
-H "Authorization: bearer $ACCESS_TOKEN"
From the response extract the user attributes for example as follows:
jq -r .[].attributes
To retrieve custom user attributes via the userinfo endpoint you need to create a protocol Mapper for the client used to authenticate the user.
That mapper can also be created with the Keycloak Admin rest API. For a more detailed answer on how to create Protocol Mappers for user-attributes (including for the old and new Keycloak APIs) please have a look at the this SO answer.
Or you can do it via Keycloak Admin UI as follows, in the Keycloak go to:
Select your realm
Go to clients
Select the appropriate client for your use-case
(For the OLD Keycloak UI)
Go to Mappers
Click Create
Select Mapper Type as User Attribute
Fill up the field User Attribute with your custom user attribute
Set to be added to the userinfo endpoint
Fill up the remaining fields, accordingly
Click on Save
(For the NEW Keycloak UI)
Go to the tab Client Scopes
Click on the scope -dedicated (e.g., test-dedicated in my example)
Click on Configure a new mapper (or Add Mapper > By configuration if you have already created mappers before for this client)
Select User Attribute
Fill up the field User Attribute with your custom user attribute
Set to be added to the userinfo endpoint
Fill up the remaining fields, accordingly
Click on Save
This is enough to enabled your custom user attribute to be retrieved from the userinfo endpoint

Keycloak is it possible acess resource server from public client

I am very new to keycloak and I want to know is it possible to create public client then authorize client and get access token. Then use that access token and create UMA tickets to resource server and check if client has rights to access resoucrces using same authorization
I uses this turtorial
https://gruchalski.com/posts/2020-09-05-introduction-to-keycloak-authorization-services/
And it worked if you reauthorized to resource server directly.
But I want to use one authorisation to check rights to resources which could belong to different resource servers
I get access token using this code:
export access_token=`curl --silent -u public-client:1 \
-k -d "grant_type=password&username=${USER_NAME}&password=${USER_PASSWORD}&scope=email profile" \
-H "Content-Type:application/x-www-form-urlencoded" \
${KEYCLOAK_TOKEN_URL} | jq '.access_token' -r`
Then I try to authorise same user to different client:
curl --silent -X POST \
${KEYCLOAK_TOKEN_URL} \
-H "Authorization: Bearer ${access_token}" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience=resource-server-1"
But I get "Client does not support permissions"
Maybe someone knows what I need to configure for this to work or even if this can work?
For what I've reading you need two clients. One public and the other confidential.
Then in your client configured as confidential set all your fine-grained authz then in your audience param you set the client id previously configured as confidential.

IBM Cloud User Management API - Invite users - Forbidden

i'm getting an error while trying to invite a user to an ibm cloud account by REST API.
The error says that the IMS account is not valid.
Does anyone know whats an IMS Account?
here is my request:
curl -X POST \
https://user-management.cloud.ibm.com/v2/accounts/&MYACCOUNT/users \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"users": [
{
"email": "myuser#ibm.com",
"account_role": "Member"
}],
"iam_policy": [
{
"roles": [
{
"id": "crn:v1:bluemix:public:iam::::role:Viewer"
}]
}]
}'
And the respsonse:
{
"trace": "558156745",
"errors": [
{
"code": 9999,
"message": "Not Authenticated.",
"more_info": "IMS account id from token is incorrect."
}
]
}
Any ideas how to handle this ?
API keys on IBM Cloud are tied to either a user or can be for a service ID, a specific service and more. The API keys for user IDs and service IDs can be used to generate an IAM (authentication) token.
When you call into a REST API and use a token, it is checked that the token is not expired, belongs to a valid user and if the required privileges are held to execute that desired function.
If you want to invite a user to an account and want to grant privileges as part of that invitation process, you would need to use a user ID with the privilege to invite to that specific account. It can be different for any account in an enterprise hierarchy, including the enterprise account. On top of that, the privileges to grant the desired roles or resource access is needed. If one is missing, it gives an error message (not always the best).

Authenticate postgrest api through keycloak

Postgrest APIs can be secured through inbuilt JWT tokens or through a third party service like Auth0, Okta or Keycloak (http://postgrest.org/en/v5.0/install.html)
We want to consume JWT provided by a Keycloak only , but there is very limited document available.
Can anybody guide me how can I secure postgrest apis through keycloak ?
thanks
UPDATE: Simple method with curl examples
Install keycloak, add realm and client
get the keys
curl https://$KEYCLOAK_URL/auth/realms/$REALM/protocol/openid-connect/certs
copy the first element of the keys array and use it in the postgrest configuration for the jwt-secret variable
use .preferred_username as the value of role-claim-key in postgrest configuration
Assuming you 've done the above you can test your installation:
Get token
curl -X POST https://$KEYCLOAK_URL/auth/realms/$REALM/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=$USERNAME" \
-d "password=$PASSWORD" \
-d 'grant_type=password' \
-d "client_id=$CLIENT"
Use the access_token element of the reply for your requests to postgrest
curl -H "Authorization: Bearer $ACCESS_TOKEN" $POSTGREST_URL/your_table
There are several ways to do it, I'll just describe one:
Set up keycloak to pass the claims you want in the token. ( Probably you would want a claim of type "role": "username" )
Get the key keycloak is using and pass it in the jwt-secret section of the postgrest configuration
Set up a web server to communicate with keycloak and get the tokens.
Pass the token to the browser
Use the token to access postgrest
Details
In keycloak admin console go to: /#/realms/<realm name>/clients/<client id>/mappers and set the claims you want
In keycloak admin console at #/realms/<realm name>/keys you can get your rsa public key, translate it to jwk format and save it to the postgrest configuration. In order to translate it to jwk
Translate it to pem format by enclosing it in -----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
Translate it to jwk format. A nice tool pem-jwk
There are infinite options. A node js example: https://github.com/keycloak/keycloak-nodejs-connect/tree/master/example that uses the keycloak-connect package
You can read the token at req.kauth.grant and place it at a hidden field of the html you send to the browser
From the browser read the token and place it at the authentication header with the bearer prefix. If you use axios:
axios({
method: 'get',
url: 'your url',
headers: { 'authorization': `Bearer ${token}` }
})

Access Keycloak REST Admin API using a service account (client credential grant)

I like to manage keycloak from my own application:create user & clients, display users & client. As this is not a real user but a machine I would like to use a service account with a client credential grant as proposed in How to get Keycloak users via REST without admin account . To realize this I:
create a realm
inside the real created a client
configured the access type of the client to "confidential" saved and activated the "Service Accounts Enabled" option that will apear after the save.
enable under scopes the client-roles of the "real-management" (see screenshot)
requested an access token with the "username:password" base64 encoded in the header
curl -X POST 'http://accounts.d10l.de/auth/realms/d10l/protocol/openid-connect/token' \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic ZGV2ZWxvcGVyLXBvcnRhbDpmZGRmYzM4Yy05MzAyLTRlZmQtYTM3Yy1lMWFmZGEyMmRhMzc=" \
-d 'grant_type=client_credentials' \
| jq -r '.access_token'
Try to access the users using the access token:
curl -I GET 'http://accounts.d10l.de/auth/admin/realms/d10l/users/' \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxRVdoNENFUjIweDY5SlBCekU4dU9GdXF4R2NVNlVfWmpTNTQ5bmd2QjNjIn0.eyJqdGkiOiI0NDM0ZDFhNS0xZTA5LTQ4MzQtYWI2Yy0zOTk1YmEwMTgxMzAiLCJleHAiOjE1MzY0MzYwMDEsIm5iZiI6MCwiaWF0IjoxNTM2NDM1NzAxLCJpc3MiOiJodHRwOi8vYWNjb3VudHMuZDEwbC5kZS9hdXRoL3JlYWxtcy9kMTBsIiwiYXVkIjoiZGV2ZWxvcGVyLXBvcnRhbCIsInN1YiI6IjliYWI0YWM1LTRiNWMtNGIxOS05ZTc3LWFjOWFmNzlkNzFhZiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImRldmVsb3Blci1wb3J0YWwiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiIyOWM2YWI3Mi05N2RiLTQ2NWUtYTE1Yy03ZWE5NzA0NmZlYzQiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbXSwicmVzb3VyY2VfYWNjZXNzIjp7fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJkZXZlbG9wZXItcG9ydGFsIiwiY2xpZW50SG9zdCI6IjE3Mi4xNy4wLjEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1kZXZlbG9wZXItcG9ydGFsIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xNy4wLjEiLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC1kZXZlbG9wZXItcG9ydGFsQHBsYWNlaG9sZGVyLm9yZyJ9.D_XnpF1rwCayup8h4UXM4AGWkY_xQo40X-yIlWhmqaxkVh1FQy24932VDRCAmxYHcrwazRMqO7snXmre3_8YF5R9Dt8GYjiBorECvQ9X_nBwunmHqnGxIeE64c2GXiz6zSjdgQJQE8fH10NsLyFWHQ-lBPsBwZBsrkKQ5QUEU2qjE7rDRPtYLJPB94BSE4QGfedmRIbvg39snVkClBDUmuBTq_Rc4p7kV69h0a2Mb1sgEr3MdB4RcsOe3gJPZVVtu7gZuGqcAQKMYgtybArF3OXz37w8hjUp6FABxDcvY7K-jsGxXn0hSU0OB7wxAWY9vP4ar4tQYlKxNjs46rPLWw"
But the response is a 403:
url: (6) Could not resolve host: GET
HTTP/1.1 403 Forbidden
content-length: 0
date: Sat, 08 Sep 2018 19:42:06 GMT
How/Is it possible accessing the Admin REST API from a new service account through a client credential grant?
Keycloak differentiates between the Scopes/Scope mapping & the roles management.
The Scopes tab: you see in the question above only manages the roles that a client is allowed to request.
For the client credential grant to work these roles must be assigned to the client in the "Service Account Roles" Tab.
So in the end the client receive a token that is the intersection of both of those configurations.
Source: https://www.keycloak.org/docs/latest/server_admin/index.html#_service_accounts