I encountered this situation where I had to onboard users into my application. The user onboarding includes creating a new application user, authenticating, and allowing the user into the application. We have two options for this: creating the identity management service ourselves or using an open-source identity and access management framework. Numerous identity provider management frameworks are available for this purpose. I used Keycloak.
Here, I want to fetch user details other than just the username and password and it is best to retain the user data within our database as well. So instead of entirely depending on Keycloak’s interface, I used the Keycloak admin API to tap into Keycloak and create the user and store the copy of user data in my database as well.
Now, Keycloak plays a major part in handling authentication and our database becomes the source of truth for the application data.
Configuring user and role management in Keycloak can be done by either using the Keycloak GUI or using the admin rest API.
Using Keycloak GUI
Login to keycloak
Tap into the keycloak administration console
Select the realm, eg: master
To create a user, click on Users from the left navigation pane.
To create roles, select the required client under which the role has to be created and click on the roles tab.
To associate a role with the user, click the user, select the role-mapping tab, and assign the roles to the user
Using Keycloak admin APIs
Keycloak Admin API provides a set of REST APIs to be consumed and used within any application. Keycloak exposes APIs for every operation that is possible within the Keycloak interface. Refer to for the API list. Keycloak provides the specific request and response data associated with each endpoint. The APIs can be consumed within the application using the access token which is obtained from keycloak.
There are two ways to get the access token,
Password Grant (not recommended)
This will require us to include the admin username and password in the request. I don’t prefer using the master username and password and feel using a Client Credentials grant time will be a better approach.
To be able to create a new user account using REST API, we will need to first acquire an access token from the Keycloak server. To acquire an access token, we can use the admin user name and password of the master realm.
curl --location --request POST 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=admin2' \
--data-urlencode 'password=admin2' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=admin-cli'
Where,
— is a host and a port number on which the Keycloak server is running. Update these values to be relevant to your setup.
/auth/realms/master/protocol/OpenID-connect/token — is a URL path to request an access token. Notice that this URL path is using the “master” realm. Do not change this URL path.
username, and password — This should be the username and password you use to log in to a Keycloak Administration console “master” realm. Update these values to be relevant to your configuration.
The grant_type — Must be “password“. Do not change this value,
and the client_id — Must be “admin-cli“. Do not change this value as well.
If the request is successful, in response you should get an access token.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2d1pGSUtKWVgwWnZRVmhtV0FLZ1JLZkZvbldzRk4tdjltT09QYlJ5Zjg4In0.eyJleHAiOjE2NzYyMTEyMzQsImlhdCI6MTY3NjIxMDkzNCwianRpIjoiNjI5MmQ5YTQtYmVmMy00ZTkzLWFmNDYtOTIyMmZmOWRiYmU5IiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5pcXpzeXN0ZW1zLmlvL3JlYWxtcy9mb3Jtcy1uZXh0LXN0YWdpbmciLCJzdWIiOiIxYWNmMGMwNC03YjU2LTRhY2YtYmVhMC04NDBiOWE0MjYwMWMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZG1pbi1jbGkiLCJhY3IiOiIxIiwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRIb3N0IjoiMTAuMTQyLjE1LjIwOSIsImNsaWVudElkIjoiYWRtaW4tY2xpIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWFkbWluLWNsaSIsImNsaWVudEFkZHJlc3MiOiIxMC4xNDIuMTUuMjA5In0.EJWb-pOSS7GQOjBqbrUpTuBn66M90EmTcomg__6Yeo63BgA7bi2vr9zZgrbSXQZRsOqwNDnEdYIa8TyYXSKuTyIUCUxDK13SXcu4HAl2lhfT93rpqqU6cYV0Zhbs_Q27dJIk6myA6L7FcHF7G1VEBfb8PeDIAFO5PjifcaAfMi6ICYHqhKWoyoZF5zPCjQYtJqg7VO3TV_wL4C4qxH7BtcsjBQNjH431UD-J9LqRR244gHQjUwhGjuiHie2mo2EtdCUDi0ps8i1EdGxjAB7-bD33l2Bmr0zgnRaVUnflA5nlcJDiX5hWR62LeDZnSNxp7OrJNIp-nJqJuO-gf5vb_Q",
"expires_in": 300,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "profile email"
}
- User Client Credentials Grant
User client credentials are the recommended way to fetch the access token.
Client Credentials grant type allows us to request an admin access token by providing a client ID and client secret instead of an admin username and password. To use this approach, the client called “admin-cli” which is in the “master” Keycloak realm needs to be set to “confidential“.
To change the “admin-cli” client Access Type property from Public to Confidential, and save the settings. You will need to log in to “master” Realm, switch to the OAuth 2 “Clients” list, and edit the “admin-cli“. Change the Access Type property from Public to Confidential and make sure that the “Service Accounts Enabled” option is turned on. Once you are done making the above changes, click on the Save button. The page will reload and at the top, you will see a new tab called “Credentials“. Click on the Credentials tab and copy the value of client_secret.
Now when you have the client secret value for OAuth 2 Client “admin-cli“, you can request an admin access token using the “client-credentials” grant type
curl --location --request POST 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=admin-cli' \
--data-urlencode 'client_secret=7fb49e15-2a86-4b7c-a648-277'-
If the request is successful, in response you should get an access token.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2d1pGSUtKWVgwWnZRVmhtV0FLZ1JLZkZvbldzRk4tdjltT09QYlJ5Zjg4In0.eyJleHAiOjE2NzYyMTEyMzQsImlhdCI6MTY3NjIxMDkzNCwianRpIjoiNjI5MmQ5YTQtYmVmMy00ZTkzLWFmNDYtOTIyMmZmOWRiYmU5IiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5pcXpzeXN0ZW1zLmlvL3JlYWxtcy9mb3Jtcy1uZXh0LXN0YWdpbmciLCJzdWIiOiIxYWNmMGMwNC03YjU2LTRhY2YtYmVhMC04NDBiOWE0MjYwMWMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhZG1pbi1jbGkiLCJhY3IiOiIxIiwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRIb3N0IjoiMTAuMTQyLjE1LjIwOSIsImNsaWVudElkIjoiYWRtaW4tY2xpIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWFkbWluLWNsaSIsImNsaWVudEFkZHJlc3MiOiIxMC4xNDIuMTUuMjA5In0.EJWb-pOSS7GQOjBqbrUpTuBn66M90EmTcomg__6Yeo63BgA7bi2vr9zZgrbSXQZRsOqwNDnEdYIa8TyYXSKuTyIUCUxDK13SXcu4HAl2lhfT93rpqqU6cYV0Zhbs_Q27dJIk6myA6L7FcHF7G1VEBfb8PeDIAFO5PjifcaAfMi6ICYHqhKWoyoZF5zPCjQYtJqg7VO3TV_wL4C4qxH7BtcsjBQNjH431UD-J9LqRR244gHQjUwhGjuiHie2mo2EtdCUDi0ps8i1EdGxjAB7-bD33l2Bmr0zgnRaVUnflA5nlcJDiX5hWR62LeDZnSNxp7OrJNIp-nJqJuO-gf5vb_Q",
"expires_in": 300,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "profile email"
}
Now we have the access token to use the admin APIs. As we are talking about the user onboarding flow, we can get started with the API to create a user into the keycloak from our application.
Here, I’m planning to fetch the basic user details like name, email, mobile number, and password.
The process will be like the user will be created in keycloak using the API and in our database using our internal API. The password management by keycloak makes it easy for us to not worry about securing the password in a place like a vault.
Endpoint :
POST /{realm}/users
The request body for creating the user would look like this,
curl --location --request POST 'http://localhost:8080/auth/admin/realms/test/users' \
--header 'Authorization: Bearer oTBKKZwFgRmW/0xN1SvF/rua=EiTnXzIf30qVZ4zdM38d-kQUS0!7q7Oq6uLKqZZ4!KO3GCEd8gbFPNDqXa3rs=UMyIMrkUTE0mdXnq3PR7nJ2/kAnRlly5N5QCqnlnZ4XeukT31qcesJ2N2wbSGL1x/ljrVyVRyL7=hfA3GqE/C6AngvnEsz38Pl=0KIO8jXpoydLtBGdC6JAjVeMf8agTZ082SfPcpJ2j6FRM4MAZJlR3CKQAoazfU6-orKE?B' \
--header 'Content-Type: application/json' \
--data-raw '{
"firstName": "test",
"lastName": "user",
"username": "testuser@gmail.com",
"email": "testuser@gmail.com",
"emailVerified": false,
"enabled": false
}'
The email verified and enabled can be set to false by default. Verification can be handled in a separate process and the email verified and enabled can be set to true.
We can configure keycloak to not accept the user login which is not email verified and not enabled
On successful request, the response will be returned as 201 Created.
Now that the user is successfully created within keycloak, the Create user will be executed using the internal API and the user will be stored in our database. By this, the keycloak and our database will remain in sync always. We can handle the verification process and update the user in the database.
Since we created a user, I can show how to retrieve the user’s data using keycloak API.
Endpoint:
GET /{realm}/users
The request body for getting the users would look like this,
curl - location - request GET 'http://localhost:8080/auth/admin/realms/test/users' \
- header 'Authorization: Bearer oTBKKZwFgRmW/0xN1SvF/rua=EiTnXzIf30qVZ4zdM38d-kQUS0!7q7Oq6uLKqZZ4!KO3GCEd8gbFPNDqXa3rs=UMyIMrkUTE0mdXnq3PR7nJ2/kAnRlly5N5QCqnlnZ4XeukT31qcesJ2N2wbSGL1x/ljrVyVRyL7=hfA3GqE/C6AngvnEsz38Pl=0KIO8jXpoydLtBGdC6JAjVeMf8agTZ082SfPcpJ2j6FRM4MAZJlR3CKQAoazfU6-orKE?B' \
- header 'Content-Type: application/json' \
Add the bearer token fetched from the above step using open ID connect.
The response for fetching the users would be,
[
{
"id": "c44ccde3-8585-4dfb-8a17-11b6c4ffee5d",
"createdTimestamp": 1672292775572,
"username": "abc@gmail.com",
"enabled": true,
"totp": false,
"emailVerified": false,
"firstName": "33",
"lastName": "33",
"email": "abc@gmail.com",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": false,
"manage": true
}
},
{
"id": "adc22c03-b141-4b3d-b409-402aab9c221c",
"createdTimestamp": 1672125356556,
"username": "apple@gmail.com",
"enabled": true,
"totp": false,
"emailVerified": false,
"firstName": "r",
"lastName": "r",
"email": "apple@gmail.com",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": false,
"manage": true
}
}
]
We came to the end of this blog. This is how I handled the user onboarding using Keycloak Admin API. You can check out the other APIs from the keycloak API reference document.
Top comments (0)