Chuyển đến nội dung chính

Lesson 5: Roles, Permissions and Access Control

Realm roles, client roles, composite roles, role mappings for users and groups, default roles, service account roles. Fine-grained admin permissions V2, realm administration delegation, resource-specific permissions, policies and permission evaluation.

Keycloak RBAC & Fine-grained Permissions

RBAC and Fine-grained Admin Permissions V2 model in Keycloak

1. Overview of Roles in Keycloak

Roles in Keycloak is the main mechanism for decentralizing access. The application checks the user's roles (through claims in the token) to decide what the user is allowed to do. Keycloak supports two types of roles: Realm Roles and Client Roles.

Realm Roles vs Client Roles

CharacteristicsRealm RolesClient Roles
ScopeEntire realmSpecific client only
Use caseGeneral roles (Admin, User, Manager)Application-specific roles (editor, viewer)
NamespaceUnique trong realmUnique trong client
Token claimrealm_access.rolesresource_access.{client}.roles

2. Realm Roles

2.1 Realm Roles default

Keycloak creates some realm roles:

  • default-roles-{realm} — composite role contains default roles for new users

  • offline_access — allows to get offline tokens (long-term token refresh)

  • uma_authorization — permission to use UMA (User-Managed Access)

2.2 Create Realm Role

Qua Admin Console:

  1. Click Realm roles trong sidebar

  2. Click Create role

  3. Enter:

    • Role name: admin
    • Description: Full administrator access
  4. Click Save

Qua Admin CLI:

# Tạo realm roles
bin/kcadm.sh create roles -r my-company -s name=admin -s description="Full administrator access"
bin/kcadm.sh create roles -r my-company -s name=manager -s description="Manager with limited admin access"
bin/kcadm.sh create roles -r my-company -s name=user -s description="Regular user"
bin/kcadm.sh create roles -r my-company -s name=viewer -s description="Read-only access"

Xem danh sách realm roles

bin/kcadm.sh get roles -r my-company --fields name,description

Qua REST API:

# Tạo realm role
curl -s -X POST \
  "http://localhost:8080/admin/realms/my-company/roles" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "admin",
    "description": "Full administrator access",
    "composite": false
  }'

Lấy danh sách realm roles

curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'

3. Client Roles

Client roles are used when the application needs its own roles — for example, a CMS application has roles editor, author, reviewer that are different from the HR application roles.

3.1 Create Client Role

Qua Admin Console:

  1. Go to Clients → select client (for example: my-web-app)

  2. Tab Roles

  3. Click Create role

  4. Enter name and description

Qua CLI:

# Lấy client ID
CLIENT_UUID=$(bin/kcadm.sh get clients -r my-company -q clientId=my-web-app --fields id --format csv --noquotes)

Tạo client roles

bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=editor -s description="Can create and edit content"

bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=author -s description="Can create content"

bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=reviewer -s description="Can review and approve content"

bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=content-admin -s description="Full content management"

Xem client roles

bin/kcadm.sh get clients/$CLIENT_UUID/roles -r my-company --fields name,description

Qua REST API:

curl -s -X POST \
  "http://localhost:8080/admin/realms/my-company/clients/$CLIENT_UUID/roles" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "editor",
    "description": "Can create and edit content"
  }'

3.2 Client Roles trong Token

Client roles appear in the access token under claim resource_access:

{
  "realm_access": {
    "roles": ["user", "offline_access"]
  },
  "resource_access": {
    "my-web-app": {
      "roles": ["editor", "author"]
    },
    "my-api": {
      "roles": ["read", "write"]
    },
    "account": {
      "roles": ["manage-account", "view-profile"]
    }
  }
}

4. Composite Roles

Composite roles are roles that contain one or more child roles (realm roles and/or client roles). When a user is assigned a composite role, the user automatically has all child roles.

4.1 Create Composite Role

Qua Admin Console:

  1. Go to Realm roles → select role (for example: admin)

  2. Tab Action → Add associated roles

  3. Select the roles to add (realm roles and/or client roles)

  4. Click Assign

Qua CLI:

# Tạo composite role: "manager" chứa "user" và "viewer"
bin/kcadm.sh add-roles \
  -r my-company \
  --rname manager \
  --rolename user \
  --rolename viewer

Thêm client roles vào composite role

bin/kcadm.sh add-roles
-r my-company
--rname manager
--cclientid my-web-app
--rolename editor
--rolename reviewer

Example hierarchy:

admin (composite)
├── manager (composite)
│   ├── user (realm role)
│   ├── viewer (realm role)
│   ├── my-web-app/editor (client role)
│   └── my-web-app/reviewer (client role)
├── my-web-app/content-admin (client role)
└── account/manage-account (client role)

Note: When a user is assigned the role admin, the user will have all roles in the hierarchy: admin, manager, user, viewer, editor, reviewer, content-admin, manage-account.

4.2 Xem Composite Roles

# Xem roles con của composite role
bin/kcadm.sh get-roles -r my-company --rname admin --effective

REST API

curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin/composites"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'

5. Role Mappings

5.1 Assign Role to User

Qua Admin Console:

  1. Go to Users → select user

  2. Tab Role mapping

  3. Click Assign role

  4. Select realm roles or filter by client to select client roles

  5. Click Assign

Qua CLI:

# Gán realm roles cho user
bin/kcadm.sh add-roles \
  -r my-company \
  --uusername john.doe \
  --rolename admin

Gán client roles cho user

bin/kcadm.sh add-roles
-r my-company
--uusername john.doe
--cclientid my-web-app
--rolename editor

Xem roles của user (bao gồm effective roles từ composite và groups)

bin/kcadm.sh get-roles
-r my-company
--uusername john.doe
--effective

Qua REST API:

# Lấy role representation
ROLE_ID=$(curl -s -X GET \
  "http://localhost:8080/admin/realms/my-company/roles/admin" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq -r '.id')

ROLE_NAME=$(curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq -r '.name')

Gán realm role cho user

curl -s -X POST
"http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/realm"
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Content-Type: application/json"
-d "[$(curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin"
-H "Authorization: Bearer $ACCESS_TOKEN")]"

5.2 Assign Role to Group

When assigning a role to a group, all members of the group (and sub-groups) will inherit that role:

# Qua CLI
bin/kcadm.sh add-roles \
  -r my-company \
  --gname Engineering \
  --rolename user

bin/kcadm.sh add-roles \
  -r my-company \
  --gname Engineering \
  --cclientid my-web-app \
  --rolename viewer

# Qua REST API
curl -s -X POST \
  "http://localhost:8080/admin/realms/my-company/groups/$GROUP_ID/role-mappings/realm" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "[$(curl -s -X GET \
    "http://localhost:8080/admin/realms/my-company/roles/user" \
    -H "Authorization: Bearer $ACCESS_TOKEN")]"

5.3 Effective Roles

Effective roles of user = directly assigned roles + roles inherited from groups + roles from composite roles:

# Xem effective realm roles
curl -s -X GET \
  "http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/realm/composite" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'

Xem effective client roles

curl -s -X GET
"http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/clients/$CLIENT_UUID/composite"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'

6. Default Roles

Default roles are automatically assigned to every new user when creating an account or registering.

6.1 Configure Default Roles

Qua Admin Console:

  1. Enter Realm roles

  2. Find the role default-roles-{realm} (for example: default-roles-my-company)

  3. Click on role → tab Action → Add associated roles

  4. Select the role you want to set as default

Qua CLI:

# Thêm role vào default roles
bin/kcadm.sh add-roles \
  -r my-company \
  --rname default-roles-my-company \
  --rolename user \
  --rolename offline_access

Thêm client role vào default roles

bin/kcadm.sh add-roles
-r my-company
--rname default-roles-my-company
--cclientid my-web-app
--rolename viewer

After that, every newly created user will automatically have roles: user, offline_access, my-web-app/viewer.

7. Service Account Roles

Service accounts are used for communication between services (machine-to-machine) — no user interaction required.

7.1 Enable Service Account for Client

  1. Go to Clients → select or create client

  2. Tab Settings:

    • Client authentication: ON
    • Service accounts roles: ON
    • Authorization: OFF (unless authorization services are needed)
  3. Click Save

7.2 Assign Role to Service Account

# Qua Admin Console:
# Clients → chọn client → tab "Service account roles" → Assign role

Qua CLI - lấy service account user

SA_USER_ID=$(bin/kcadm.sh get clients/$CLIENT_UUID/service-account-user -r my-company --fields id --format csv --noquotes)

Gán realm roles

bin/kcadm.sh add-roles
-r my-company
--uid $SA_USER_ID
--rolename admin

Gán client roles (realm-management) cho API access

bin/kcadm.sh add-roles
-r my-company
--uid $SA_USER_ID
--cclientid realm-management
--rolename manage-users
--rolename view-users
--rolename manage-clients

7.3 Using Service Account

# Lấy access token cho service account (client credentials grant)
ACCESS_TOKEN=$(curl -s -X POST \
  "http://localhost:8080/realms/my-company/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=my-backend-service" \
  -d "client_secret=YOUR_CLIENT_SECRET" | jq -r '.access_token')

Sử dụng token để gọi API

curl -s -X GET
"http://localhost:8080/admin/realms/my-company/users"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].username'

8. Fine-grained Admin Permissions V2

Fine-grained admin permissions V2 (from Keycloak 26+) allows granular control over who can manage which resources in the Admin Console — instead of just using raw realm-management client roles.

8.1 Enable Fine-grained Admin Permissions

  1. Go to Realm settings → General

  2. Find Admin Permissions → enable Fine-grained admin permissions (V2)

  3. Keycloak will create permission management resources in realm

Note: This is a preview feature in Keycloak 26.x. In production, you need to evaluate carefully before turning on.

8.2 Resource Permissions

Once enabled, you can create permissions for resources:

Users permissions:

PermissionDescription
viewView list and details users
manageCreate, edit, delete users
map-rolesAssign/remove roles to users
manage-group-membershipAdd/remove users from groups
impersonateImpersonate users

Groups permissions:

PermissionDescription
viewXem groups
manageCreate, edit, delete groups
view-membersView members of group
manage-membersAdd/remove members
manage-membershipManage group membership

Clients permissions:

PermissionDescription
viewXem clients
manageCreate, edit, delete clients
configureChange client settings
map-rolesCreate/assign client roles

Roles permissions:

PermissionDescription
viewXem roles
manageCreate, edit, delete roles
map-roleAssign roles to users/groups

8.3 Create Permission

  1. Go to Realm settings → Admin permissions

  2. Select resource type (Users, Groups, Clients, Roles)

  3. Click on the permission to configure (for example: manage for Users)

  4. Add policies to determine who has this permission

8.4 Policies

Policies defines the conditions for granting permission. Keycloak V2 supports the following policies:

Role-based Policy:

// Cho phép users có role "hr-admin" quản lý users
{
  "type": "role",
  "name": "HR Admin Policy",
  "description": "Users with hr-admin role",
  "roles": [
    {
      "id": "{role-id-of-hr-admin}",
      "required": true
    }
  ]
}

User-based Policy:

// Cho phép specific users
{
  "type": "user",
  "name": "Specific Admin Policy",
  "users": [
    "{user-id-of-admin-1}",
    "{user-id-of-admin-2}"
  ]
}

Group-based Policy:

// Cho phép members của group
{
  "type": "group",
  "name": "Admin Group Policy",
  "groups": [
    {
      "id": "{group-id-of-admins}",
      "extendChildren": true
    }
  ]
}

Client-based Policy:

// Cho phép specific clients (service accounts)
{
  "type": "client",
  "name": "Backend Service Policy",
  "clients": [
    "{client-id-of-backend-service}"
  ]
}

8.5 Practical example: HR Admin only manages Users

Requirement: User with role hr-admin is only allowed to view and manage users, not manage clients or realm settings.

  1. Create realm role hr-admin:

    bin/kcadm.sh create roles -r my-company \
      -s name=hr-admin \
      -s description="HR Administrator - can manage users only"
  2. Enable Fine-grained admin permissions V2

  3. Create Role-based Policy for hr-admin:

    • Go to Admin permissions → Policies tab
    • Create policy → Role-based
    • Name: "HR Admin Policy"
    • Select role: hr-admin
  4. Assign policy to Users permissions:

    • Users → permission view → Add policy "HR Admin Policy"
    • Users → permission manage → Add policy "HR Admin Policy"
  5. Assign role to user:

    bin/kcadm.sh add-roles -r my-company \
      --uusername hr-manager \
      --rolename hr-admin

Now user hr-manager can log in to Admin Console and only see menu Users.

8.6 Permission Evaluation

You can test permissions using the Evaluation tab:

  1. Go to Admin permissions → Evaluate

  2. Select the user or client to test

  3. Select resource type and permission

  4. Click Evaluate to see the result (PERMIT or DENY)

9. Dedicated Realm Admin Consoles

Keycloak allows creating separate admin accounts for each realm — no need to access the master realm:

9.1 Create Realm Admin

# Tạo user trong realm
bin/kcadm.sh create users -r my-company \
  -s username=realm-admin \
  -s [email protected] \
  -s enabled=true \
  -s emailVerified=true

bin/kcadm.sh set-password -r my-company
--username realm-admin
--new-password "RealmAdmin@123"

Gán realm-management client roles

bin/kcadm.sh add-roles -r my-company
--uusername realm-admin
--cclientid realm-management
--rolename realm-admin

9.2 Realm Management Client Roles

Client realm-management has available roles to control admin rights:

RoleDescription
realm-adminFull admin access cho realm
manage-usersManage users
view-usersXem users
manage-clientsManage clients
view-clientsXem clients
manage-realmManage realm settings
view-realmXem realm settings
manage-identity-providersManage identity providers
manage-eventsManage events
manage-authorizationManage authorization
impersonationImpersonate users
query-usersSearch users
query-groupsSearch groups
query-clientsSearch clients
query-realmsSearch realms

For example: Create a limited admin that only manages users and groups:

bin/kcadm.sh add-roles -r my-company \
  --uusername limited-admin \
  --cclientid realm-management \
  --rolename manage-users \
  --rolename view-users \
  --rolename query-users \
  --rolename query-groups

10. Using Roles in application

10.1 Check Roles from Access Token

Decoded access token contains roles:

{
  "sub": "user-uuid",
  "realm_access": {
    "roles": [
      "admin",
      "manager",
      "user",
      "default-roles-my-company",
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "my-web-app": {
      "roles": [
        "editor",
        "content-admin"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  }
}

10.2 Example in Spring Boot

// SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/admin/**").hasRole("admin")
            .requestMatchers("/api/content/**").hasRole("editor")
            .requestMatchers("/api/public/**").permitAll()
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt
                .jwtAuthenticationConverter(jwtAuthenticationConverter())
            )
        );
    return http.build();
}

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
    converter.setAuthoritiesClaimName("realm_access.roles");
    converter.setAuthorityPrefix("ROLE_");
    
    JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
    jwtConverter.setJwtGrantedAuthoritiesConverter(converter);
    return jwtConverter;
}

}

10.3 Example in Node.js (Express)

// middleware/auth.js
const jwt = require('jsonwebtoken');

function hasRealmRole(role) { return (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token provided' });

try {
  const decoded = jwt.decode(token);
  const roles = decoded.realm_access?.roles || [];
  
  if (roles.includes(role)) {
    req.user = decoded;
    next();
  } else {
    res.status(403).json({ error: 'Insufficient permissions' });
  }
} catch (err) {
  res.status(401).json({ error: 'Invalid token' });
}

}; }

function hasClientRole(clientId, role) { return (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token provided' });

try {
  const decoded = jwt.decode(token);
  const roles = decoded.resource_access?.[clientId]?.roles || [];
  
  if (roles.includes(role)) {
    req.user = decoded;
    next();
  } else {
    res.status(403).json({ error: 'Insufficient permissions' });
  }
} catch (err) {
  res.status(401).json({ error: 'Invalid token' });
}

}; }

// Sử dụng app.get('/api/admin/users', hasRealmRole('admin'), (req, res) => { // Only admin can access });

app.post('/api/content', hasClientRole('my-web-app', 'editor'), (req, res) => { // Only editors can create content });

11. Practice exercises

  1. Create Realm Roles: super-admin, manager, staff, viewer

  2. Create Client Roles for client my-web-app: content-editor, content-reviewer, content-publisher

  3. Create Composite Roles:

    • super-admin contains: manager + all client roles
    • manager contains: staff + content-reviewer
    • staff contains: viewer + content-editor
  4. Assign roles to groups:

    • Group Engineering: realm role staff
    • Group Engineering/Backend: client role content-editor
  5. Enable Fine-grained admin permissions V2 and create:

    • Role-based policy cho hr-admin
    • Assign policy to Users view/manage permissions
    • Test with user with role hr-admin
  6. Create Service Account for client my-backend-service with roles manage-users, view-users and test with client credentials grant

12. Summary

In this lesson, you learned:

  • Distinguish between Realm Roles and Client Roles

  • Create Composite Roles with hierarchy

  • Role Mappings for users and groups (direct and legacy)

  • Configuration Default Roles for new users

  • Use Service Account Roles for machine-to-machine communication

  • Fine-grained Admin Permissions V2 with policies (role-based, user-based, group-based, client-based)

  • Create dedicated realm admin with limited permissions

  • Check roles in the application (Spring Boot, Node.js)

The next article will guide about Clients, Client Scopes and OpenID Connect in Keycloak.