<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Santhiya G</title>
    <description>The latest articles on DEV Community by Santhiya G (@im_santhiya_guna).</description>
    <link>https://dev.to/im_santhiya_guna</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2275313%2F4f39ab68-aa83-45ab-9e45-82fdc3e76d55.jpg</url>
      <title>DEV Community: Santhiya G</title>
      <link>https://dev.to/im_santhiya_guna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/im_santhiya_guna"/>
    <language>en</language>
    <item>
      <title>Handling nested roles in Keycloak</title>
      <dc:creator>Santhiya G</dc:creator>
      <pubDate>Sat, 02 Nov 2024 07:42:17 +0000</pubDate>
      <link>https://dev.to/im_santhiya_guna/handling-nested-roles-in-keycloak-3lfk</link>
      <guid>https://dev.to/im_santhiya_guna/handling-nested-roles-in-keycloak-3lfk</guid>
      <description>&lt;p&gt;I came up with this situation where I had to set permissions for every API within my application and associate a role for every user in the application. This user role should contain the combination of permissions that were set to the APIs.&lt;br&gt;
In Keycloak there is no separate thing called permission. All the permissions are treated as roles. But there is a way to create sub-roles within a role. So I created API permissions as sub-roles and associated them with the user roles.&lt;/p&gt;

&lt;p&gt;We’ll discuss how to create roles, associate them with nested roles, and assign these roles to the user. I will create the role using API. For this, we need the access token. We can get the access token using the client credentials grant method below&lt;/p&gt;

&lt;p&gt;User client credentials are the recommended way to fetch the access token.&lt;/p&gt;

&lt;p&gt;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 “&lt;em&gt;admin-cli&lt;/em&gt;” which is in the “&lt;em&gt;master&lt;/em&gt;” Keycloak realm needs to be set to “&lt;em&gt;confidential&lt;/em&gt;“.&lt;/p&gt;

&lt;p&gt;To change the “&lt;em&gt;admin-cli&lt;/em&gt;” client &lt;strong&gt;Access Type&lt;/strong&gt; property from &lt;em&gt;Public&lt;/em&gt; to &lt;em&gt;Confidential&lt;/em&gt;, and save the settings. You will need to log in to “&lt;em&gt;master&lt;/em&gt;” Realm, switch to the OAuth 2 “Clients” list, and edit the “admin-cli“. Change the &lt;strong&gt;Access Type&lt;/strong&gt; property from &lt;em&gt;Public&lt;/em&gt; to &lt;em&gt;Confidential&lt;/em&gt; and make sure that the &lt;strong&gt;“Service Accounts Enabled”&lt;/strong&gt; option is turned on. Once you are done making the above changes, click on the &lt;strong&gt;Save&lt;/strong&gt; button. The page will reload and at the top, you will see a new tab called “&lt;em&gt;Credentials&lt;/em&gt;“. Click on the &lt;strong&gt;Credentials tab&lt;/strong&gt; and copy the value of &lt;strong&gt;client_secret&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now when you have the client secret value for OAuth 2 Client “&lt;em&gt;admin-cli&lt;/em&gt;“, you can request an admin access token using the “&lt;em&gt;client-credentials&lt;/em&gt;” grant type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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'-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the request is successful, in response you should get an access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "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"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create Role&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Roles can be either Realm level or client level. The realm-level roles can be applied to users in any client within the realm. The client-level roles are restricted to the client's scope.&lt;/p&gt;

&lt;p&gt;Here, we can create roles within the client. The role can either be a base role or a sub-role. Keycloak treats all these roles as common roles.&lt;/p&gt;

&lt;p&gt;To create roles within the client we need the id of the client. The id of the client is not the same as the client's id. First, we have to fetch the client ID.&lt;/p&gt;

&lt;p&gt;The request body to fetch the client ID would look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request GET 'http://localhost:8080/auth/admin/realms/test/clients?clientId=demo_app' \
- header 'Authorization: Bearer oTBKKZwFgRmW/0xN1SvF/rua=EiTnXzIf30qVZ4zdM38d-kQUS0!7q7Oq6uLKqZZ4!KO3GCEd8gbFPNDqXa3rs=UMyIMrkUTE0mdXnq3PR7nJ2/kAnRlly5N5QCqnlnZ4XeukT31qcesJ2N2wbSGL1x/ljrVyVRyL7=hfA3GqE/C6AngvnEsz38Pl=0KIO8jXpoydLtBGdC6JAjVeMf8agTZ082SfPcpJ2j6FRM4MAZJlR3CKQAoazfU6-orKE?B' \
 - header 'Content-Type: application/json' \
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful request, the &lt;strong&gt;client ID&lt;/strong&gt; would be returned as a response. The client ID will be a UUID.&lt;/p&gt;

&lt;p&gt;We’ll start by creating a role called &lt;strong&gt;member&lt;/strong&gt; which will act as a user role and a role called &lt;strong&gt;read-access&lt;/strong&gt; which will act as API permission.&lt;/p&gt;

&lt;p&gt;Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /{realm}/clients/{id}/roles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request body for member roles would be like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request POST 'http://localhost:8080/auth/admin/realms/test/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf/roles' \
--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 '{
    "name": "member",
    "description": "member is a basic level permission",
    "composite": false
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful request, the response will be &lt;strong&gt;201 Created&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The request body for the read-access role would be like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request POST 'http://localhost:8080/auth/admin/realms/test/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf/roles' \
--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 '{
    "name": "read-access",
    "description": "read-access is a api level permission",
    "composite": false
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful request, the response will be &lt;strong&gt;201 Created&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here, both roles have the &lt;strong&gt;composite&lt;/strong&gt; parameter as &lt;strong&gt;false&lt;/strong&gt; by default, which means both roles are at the root level (base roles).&lt;/p&gt;

&lt;p&gt;Now we have to add read-access as a sub-role to the member role. This is called nested role mapping. For this, we have to update the member role with an updated request body as,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request POST 'http://localhost:8080/auth/admin/realms/test/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf/roles/member/composites' \
--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 '{
    "composite": true,
    "composites": [
        {
            "id": "c44ccde3-8585-4dfb-8a17-11b6c4ffee5d",
            "name": "read-access"
        }
    ]
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful request, nested roles will be created i.e.) member will be the base role that has read-access permission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assign roles to the user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For implementing the Role-based access control method, we have to assign the roles to the user.&lt;/p&gt;

&lt;p&gt;The request body will be like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request POST 'http://localhost:8080/auth/admin/realms/test/users/c44ccde3-8585-4dfb-8a17-11b6c4ffee5d/role-mappings/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf' \
--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 '[
    {
        "id": "c44ccde3-8585-4dfb-8a17-11b6c4ffasw",
        "name": "member"
    }
]'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On successful request, the user will be assigned the member role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fetch roles associated with the user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two ways to get the roles associated with the user. We can either decode the access token or use the API to fetch the roles.&lt;/p&gt;

&lt;p&gt;Let us decode the access token to fetch roles here,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;1wbGF0ZXM6Y3JlYXRlIiwic3Vic2NyaXB0aW9uOmNhbmNlbCIsImlxei1zeXN0ZW1zJHN1cGVyLWFkbWluIiwidXNlcjpkZWxldGUiLCIjZm9ybXM6cHVibGlzaC5zZWxmIiwiI2Zvcm1zOnB1Ymxpc2giLCJyb2xlOnJlYWQiLCIjdXNlcjp1cGRhdGUuc2VsZiIsIiN1c2VyOnVwZGF0ZSIsInN1YnNjcmlwdGlvbjp1cGRhdGUiLCJmb3Jtczp1cGRhdGUiLCJzdWJzY3JpcHRpb246Y3JlYXRlIiwicm9sZTpjcmVhdGUiLCJ0ZW1wbGF0ZXM6cmVhZCIsInBheW1lbnRzOnJlYWQiLCIjZm9ybXM6dXBkYXRlLnNlbGYiLCJwcm9mLWNvbXBhbnkkbWVtYmVyIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBVc2VyX1JlYWxtX1JvbGVfTWFwcGVyIHJvbGVzIiwic2lkIjoiYjI5ZmNiNWMtZmU3MC00NTVjLTk3MTktNDg0NzcyOTI0OGY1IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJTYW50aGl5YSBHdW5hIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2FudGhpeWEuZ0BpcXpzeXN0ZW1zLmNvbSIsImdpdmVuX25hbWUiOiJTYW50aGl5YSIsImZhbWlseV9uYW1lIjoiR3VuYSIsImVtYWlsIjoic2FudGhpeWEuZ0BpcXpzeXN0ZW1zLmNvbSJ9&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The decoded token looks like this. The roles list is available below the resource_access&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"iat": 1674584331,
  "auth_time": 1674580691,
  "jti": "e77bd9e8-3148-49f0-8fdb-8a9277defc19",
  "iss": "http://localhost:8080/auth/admin/realms/test",
  "sub": "24199ac7-3148-49f0-8fdb-a255f230dc2f",
  "typ": "Bearer",
  "azp": "test",
  "nonce": "ac12440d-26b9-4eba-8bd7-c6d088a1ee38",
  "session_state": "b29fcb5c-fe70-455c-9719-4847729248f5",
  "acr": "0",
  "allowed-origins": [
    "*"
  ],
  "resource_access": {
    "test": {
      "roles": [
        "read-access",
        "write-access",
        "member"
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using keycloak API,&lt;/p&gt;

&lt;p&gt;To fetch the role associated with the user, the request body would look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request GET 'http://localhost:8080/auth/admin/realms/test/users/c44ccde3-8585-4dfb-8a17-11b6c4ffee5d/role-mappings/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf' \
--header 'Authorization: Bearer oTBKKZwFgRmW/0xN1SvF/rua=EiTnXzIf30qVZ4zdM38d-kQUS0!7q7Oq6uLKqZZ4!KO3GCEd8gbFPNDqXa3rs=UMyIMrkUTE0mdXnq3PR7nJ2/kAnRlly5N5QCqnlnZ4XeukT31qcesJ2N2wbSGL1x/ljrVyVRyL7=hfA3GqE/C6AngvnEsz38Pl=0KIO8jXpoydLtBGdC6JAjVeMf8agTZ082SfPcpJ2j6FRM4MAZJlR3CKQAoazfU6-orKE?B' \
--header 'Content-Type: application/json' \
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fetch the composites associated with each role, the request body would look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl - location - request GET 'http://localhost:8080/auth/admin/realms/test/clients/9f1da13c-5049-43c4-9d17-113d9a4726bf/roles/member/composites' \
--header 'Authorization: Bearer oTBKKZwFgRmW/0xN1SvF/rua=EiTnXzIf30qVZ4zdM38d-kQUS0!7q7Oq6uLKqZZ4!KO3GCEd8gbFPNDqXa3rs=UMyIMrkUTE0mdXnq3PR7nJ2/kAnRlly5N5QCqnlnZ4XeukT31qcesJ2N2wbSGL1x/ljrVyVRyL7=hfA3GqE/C6AngvnEsz38Pl=0KIO8jXpoydLtBGdC6JAjVeMf8agTZ082SfPcpJ2j6FRM4MAZJlR3CKQAoazfU6-orKE?B' \
--header 'Content-Type: application/json' \
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response for getting the roles would be,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "id": "df9aaf7e-b54f-4439-9265-ace2e82561ad",
        "name": "member",
        "description": "member is a base role",
        "composite": true
    },
    {
        "id": "88b12a77-31e8-452e-a39b-5c7d1901a3e0",
        "name": "read-access",
        "description": "read permission",
        "composite": false
    },
    {
        "id": "ee43504a-8173-415a-a64b-fe44b97364b7",
        "name": "write-access",
        "description": "write permission",
        "composite": false
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have come to the end of this blog. Now, we can create a role, create a nested role within that, associate the role to the user, and fetch the roles associated either using a token or admin API. This is the basic introduction to user role management in any application.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Introduction to Keycloak Admin API</title>
      <dc:creator>Santhiya G</dc:creator>
      <pubDate>Sat, 02 Nov 2024 07:22:31 +0000</pubDate>
      <link>https://dev.to/im_santhiya_guna/introduction-to-keycloak-admin-api-273m</link>
      <guid>https://dev.to/im_santhiya_guna/introduction-to-keycloak-admin-api-273m</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Now, Keycloak plays a major part in handling authentication and our database becomes the source of truth for the application data.&lt;/p&gt;

&lt;p&gt;Configuring user and role management in Keycloak can be done by either using the Keycloak GUI or using the admin rest API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Keycloak GUI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Login to keycloak&lt;/p&gt;

&lt;p&gt;Tap into the keycloak administration console&lt;/p&gt;

&lt;p&gt;Select the realm, eg: master&lt;/p&gt;

&lt;p&gt;To create a user, click on Users from the left navigation pane.&lt;/p&gt;

&lt;p&gt;To create roles, select the required client under which the role has to be created and click on the roles tab.&lt;/p&gt;

&lt;p&gt;To associate a role with the user, click the user, select the role-mapping tab, and assign the roles to the user&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Keycloak admin APIs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://www.keycloak.org/docs-api/15.0/rest-api/index.html" rel="noopener noreferrer"&gt;&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;There are two ways to get the access token,&lt;/p&gt;

&lt;p&gt;Password Grant (not recommended)&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/strong&gt; — is a host and a port number on which the Keycloak server is running. Update these values to be relevant to your setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;/auth/realms/master/protocol/OpenID-connect/token&lt;/em&gt;&lt;/strong&gt; — 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;username, and password&lt;/strong&gt; — 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.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;grant_type&lt;/strong&gt; — Must be “password“. Do not change this value,&lt;br&gt;
and the &lt;strong&gt;client_id&lt;/strong&gt; — Must be “admin-cli“. Do not change this value as well.&lt;/p&gt;

&lt;p&gt;If the request is successful, in response you should get an access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "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"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;User Client Credentials Grant&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;User client credentials are the recommended way to fetch the access token.&lt;/p&gt;

&lt;p&gt;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“.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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'-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the request is successful, in response you should get an access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "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"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;br&gt;
Here, I’m planning to fetch the basic user details like name, email, mobile number, and password.&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;Endpoint :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /{realm}/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request body for creating the user would look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;br&gt;
We can configure keycloak to not accept the user login which is not email verified and not enabled&lt;/p&gt;

&lt;p&gt;On successful request, the response will be returned as 201 Created.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Since we created a user, I can show how to retrieve the user’s data using keycloak API.&lt;/p&gt;

&lt;p&gt;Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /{realm}/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request body for getting the users would look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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' \
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the bearer token fetched from the above step using open ID connect.&lt;/p&gt;

&lt;p&gt;The response for fetching the users would be,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "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
        }
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Strapi — Why</title>
      <dc:creator>Santhiya G</dc:creator>
      <pubDate>Fri, 01 Nov 2024 18:34:20 +0000</pubDate>
      <link>https://dev.to/im_santhiya_guna/strapi-why-562i</link>
      <guid>https://dev.to/im_santhiya_guna/strapi-why-562i</guid>
      <description>&lt;p&gt;In general, building a software or web application involves both frontend and backend. Frontend is mainly focused on user experience, whereas backend includes server and database. One important part in any application is handling data, that is posting and retrieving data. Database effectively manages data. But it has the limitation of maintaining the data in user friendly manner and the database queries are complicated for general non-technical users.&lt;/p&gt;

&lt;p&gt;Headless CMS provides a easiest way to store the data and maintain all the data as collections. It provides the way to manage the content in user friendly manner. So, for use cases like storing and retrieving data in a proper organized manner, headless CMS is a good choice.&lt;/p&gt;

&lt;p&gt;There are a number of content management systems available. The challenge is to select the most scalable, reliable and the appropriate one for our use cases. In that way, strapi is a good option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WHY STRAPI?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Headless CMS like strapi mainly focusses on managing the content and storing it in the database. The data can be stored in Strapi using GUI or API endpoints. The data can be retrieved and used from Strapi using the API endpoints.&lt;/p&gt;

&lt;p&gt;Strapi is the leading open-sourse headless CMS. It’s 100% Javascript, and fully customizable and developer-first. It saves API development time through a beautiful admin panel anyone can use.&lt;/p&gt;

&lt;p&gt;Strapi is an open source headless CMS, which makes it easily configurable. It provides a user friendly interface for editing content. The content can be directly posted into Strapi using the GUI. Even the non technical persons can use it easily. It provides API endpoints to access its content. Strapi provides various plugin options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features of Strapi:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-databases support:&lt;/strong&gt; Database can be picked by our choice. It supports plenty of databases like SQLite, MongoDB, MySQL, Postgres etc,.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RESTful:&lt;/strong&gt; API can be consumed by any clients like React, Angular, Vue etc, Mobile apps and even IoT using REST.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;100% Javascript:&lt;/strong&gt; Javascript fits all from frontend( React, Angular, Vue) to backend(Node js).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webhooks:&lt;/strong&gt; Call back anywhere to get the functionality we need with our API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentications and Permissions:&lt;/strong&gt; Secure the endpoints by granting permissions to the users to access a specific endpoint based on roles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-generated documentation:&lt;/strong&gt; Write and maintain the documentation with a one-click integration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customizable API:&lt;/strong&gt; Strapi not just allows us to use it’s API, it also provides the way to customize the API to fit the our needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Internationalization:&lt;/strong&gt; Strapi supports creating multilingual website or applications. It translates the content and page structure to each versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media Library:&lt;/strong&gt; Strapi provides us a way to upload, access and edit media files like images, videos, audio and documents.&lt;/p&gt;

</description>
      <category>development</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
