Implementing RBAC in Keycloak: Roles, Scopes, and Policies

Guilliano Molaire Guilliano Molaire Updated March 15, 2026 10 min read

Last updated: March 2026
Role-Based Access Control (RBAC) is the most widely adopted authorization model in enterprise software. Rather than assigning permissions directly to individual users, RBAC groups permissions into roles and assigns those roles to users. This indirection simplifies access management, improves auditability, and reduces the likelihood of permission drift as organizations scale.

Keycloak provides a comprehensive RBAC implementation that goes well beyond simple role assignment. It supports realm-level and client-level roles, composite roles, default roles, group-based role mapping, and a full authorization services engine for fine-grained policy evaluation. This guide walks through each layer, from basic role creation to advanced policy configuration, with working code examples for Spring Boot and Node.js.

If you are new to Keycloak and need a hosted environment to follow along, you can generate a ready-to-run configuration with the Keycloak Config Generator or explore the Skycloak platform documentation for managed deployment options.

RBAC Concepts in Keycloak

Before creating roles, it helps to understand how Keycloak organizes them. Keycloak distinguishes between three types of roles, each serving a different purpose.

Realm Roles vs Client Roles

Realm roles are global to the Keycloak realm. Any client application registered in the realm can reference them. Use realm roles for cross-cutting permissions that apply across multiple applications, such as admin, manager, or viewer.

Client roles are scoped to a specific client (application). They only appear in the token claims for that client. Use client roles when permissions are meaningful only within a single application. For example, a reporting service might define report-viewer and report-editor roles that have no relevance to other services in the realm.

The general guideline: start with realm roles for organization-wide access levels, and use client roles when an application has permissions that do not map to any other service.

Composite Roles

A composite role is a role that contains other roles. When a user is assigned a composite role, they automatically inherit all of the roles it contains. This is useful for building role hierarchies. For example, a super-admin composite role could include the admin realm role plus the billing-manager client role from the billing service.

Composite roles can include both realm roles and client roles from any client in the realm. Use them sparingly and document what each composite role contains, as deeply nested composites can make permission auditing difficult.

Default Roles

Default roles are automatically assigned to every new user created in the realm. Keycloak provides a built-in default-roles-{realm} composite role that you can customize. This is the right place to assign baseline permissions that every user should have, such as user or authenticated.

You can configure default roles at Realm Settings > User registration > Default roles in the Admin Console.

Setting Up Realm Roles

Creating Roles in the Admin Console

To create a realm role:

  1. Navigate to Realm roles in the left sidebar of the Admin Console.
  2. Click Create role.
  3. Enter a Role name (e.g., admin). Role names are case-sensitive and cannot contain spaces.
  4. Optionally add a Description to document what the role grants.
  5. Click Save.

Repeat this process for each role your application requires. A typical starting set might include admin, manager, and viewer.

Assigning Roles to Users

To assign a realm role to a specific user:

  1. Navigate to Users in the left sidebar.
  2. Select the user.
  3. Go to the Role mapping tab.
  4. Click Assign role.
  5. Filter by realm roles, select the desired role(s), and click Assign.

This works well for small numbers of users, but it does not scale. For organizations with hundreds or thousands of users, group-based assignment is the better approach.

Assigning Roles to Groups

Groups let you assign roles to a collection of users at once. When a user joins a group, they inherit all roles mapped to that group.

To set up group-based role assignment:

  1. Navigate to Groups in the left sidebar.
  2. Create a group (e.g., engineering).
  3. Select the group and go to the Role mapping tab.
  4. Click Assign role and select the realm roles this group should have.
  5. Add users to the group via the Members tab, or assign groups to users from the user’s Groups tab.

This approach aligns well with organizational structures. When a new engineer joins the team, adding them to the engineering group automatically grants the correct permissions. When they change teams, moving them to a different group updates their access without touching individual role assignments.

For more on managing users and groups at scale, see User Management.

Setting Up Client Roles

When Client-Specific Roles Make Sense

Client roles are appropriate when:

  • An application has permissions that are meaningless outside of that application.
  • You want to keep role namespaces separate between services.
  • Different services define overlapping role names with different semantics (e.g., editor means different things in a CMS vs. a code review tool).

Creating and Assigning Client Roles

To create a client role:

  1. Navigate to Clients in the left sidebar.
  2. Select the client application.
  3. Go to the Roles tab.
  4. Click Create role.
  5. Enter a Role name and optional Description.
  6. Click Save.

Assigning client roles to users follows the same process as realm roles. From the user’s Role mapping tab, click Assign role, then filter by the specific client to see its available roles.

Client roles can also be assigned to groups, and they can be included in composite roles. The same scalability principles apply: prefer group-based assignment over individual user assignment.

Role Mapping and Token Claims

Understanding how roles appear in JWT tokens is essential for enforcing RBAC in your application code.

How Roles Appear in JWT Tokens

By default, Keycloak includes roles in the access token under two claims:

  • realm_access.roles contains the user’s realm roles.
  • resource_access.{client-id}.roles contains the user’s client roles for each client.

Here is an example JWT payload for a user with the admin realm role and an editor client role on a client named my-app:

{
  "sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "realm_access": {
    "roles": [
      "admin",
      "default-roles-myrealm"
    ]
  },
  "resource_access": {
    "my-app": {
      "roles": [
        "editor"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "view-profile"
      ]
    }
  },
  "preferred_username": "jane.doe",
  "email": "[email protected]"
}

You can inspect token payloads interactively with the JWT Token Analyzer to verify that roles are mapped correctly.

Custom Role Mappers

Sometimes you need to change how roles appear in the token. Keycloak’s protocol mappers let you:

  • Rename claims: Move roles from realm_access to a custom claim name like roles.
  • Filter roles: Include only specific roles in the token to reduce payload size.
  • Flatten the structure: Combine realm and client roles into a single claim.

To add a custom role mapper:

  1. Navigate to Clients > select your client > Client scopes tab.
  2. Click on the dedicated scope (e.g., my-app-dedicated).
  3. Go to Mappers > Configure a new mapper.
  4. Select User Realm Role or User Client Role.
  5. Set the Token Claim Name to your preferred claim name (e.g., roles).
  6. Configure whether to add the claim to the access token, ID token, or both.
  7. Click Save.

This is particularly useful when your backend expects roles in a specific claim format that differs from Keycloak’s default structure.

Authorization Services

Keycloak’s Authorization Services provide a policy-based authorization layer that builds on top of RBAC. While basic role checking in application code works for many use cases, Authorization Services let you define and evaluate complex access rules centrally in Keycloak.

Enabling Authorization Services

Authorization Services must be enabled per client:

  1. Navigate to Clients > select your client.
  2. On the Settings tab, toggle Authorization Enabled to On.
  3. Click Save.

This adds an Authorization tab to the client where you can define resources, scopes, policies, and permissions.

Role-Based Policies

A role-based policy grants or denies access based on whether the user has a specific role.

To create one:

  1. Go to Clients > your client > Authorization > Policies tab.
  2. Click Create policy > Role.
  3. Give the policy a name (e.g., Require Admin Role).
  4. Under Realm Roles or Client Roles, select the required role(s).
  5. Set the Logic to Positive (grant if role is present) or Negative (deny if role is present).
  6. Click Save.

Combining Policy Types

The real power of Authorization Services comes from combining multiple policy types. You can create:

  • Time-based policies: Restrict access to specific hours or date ranges. For example, allow report-export only during business hours.
  • Group-based policies: Require membership in a specific group, independent of role assignment.
  • Aggregated policies: Combine multiple policies with AND/OR logic. For example, require both the admin role AND access during business hours.
  • JavaScript or regex policies: For custom logic that does not fit the built-in policy types.

To combine policies into a permission:

  1. Go to the Permissions tab under Authorization.
  2. Click Create permission > Scope-based or Resource-based.
  3. Select the resources or scopes the permission applies to.
  4. Under Policies, select one or more policies.
  5. Set the Decision Strategy to:
    • Unanimous: All policies must grant access.
    • Affirmative: At least one policy must grant access.
    • Consensus: Majority of policies must grant access.
  6. Click Save.

Permission Evaluation

You can test permission evaluation directly in the Admin Console:

  1. Go to Clients > your client > Authorization > Evaluate tab.
  2. Select a user.
  3. Optionally select specific resources and scopes.
  4. Click Evaluate.

Keycloak shows the evaluation result for each permission, including which policies granted or denied access and why. This is invaluable for debugging complex authorization configurations.

For a deeper look at Keycloak’s authorization model, including resource servers and scopes, see the RBAC feature overview.

Code Examples

Spring Boot: Role-Based Endpoint Security

Spring Security integrates with Keycloak’s JWT tokens out of the box when using spring-boot-starter-oauth2-resource-server. Here is how to protect endpoints based on realm roles.

First, configure the resource server in application.yml:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://your-keycloak.example.com/realms/your-realm

Create a security configuration that extracts Keycloak roles from the JWT:

@Configuration
@EnableMethodSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
        );
        return http.build();
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter =
            new JwtGrantedAuthoritiesConverter();

        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwt -> {
            Collection<GrantedAuthority> authorities =
                grantedAuthoritiesConverter.convert(jwt);

            Map<String, Object> realmAccess = jwt.getClaimAsMap("realm_access");
            if (realmAccess != null && realmAccess.containsKey("roles")) {
                List<String> roles = (List<String>) realmAccess.get("roles");
                authorities.addAll(roles.stream()
                    .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                    .toList());
            }
            return authorities;
        });
        return converter;
    }
}

Now you can use @PreAuthorize to protect controller methods:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping
    @PreAuthorize("hasRole('admin')")
    public ResponseEntity<List<User>> getUsers() {
        return ResponseEntity.ok(userService.findAll());
    }

    @GetMapping("/{id}")
    @PreAuthorize("hasAnyRole('admin', 'manager')")
    public ResponseEntity<User> getUser(@PathVariable String id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('admin')")
    public ResponseEntity<Void> deleteUser(@PathVariable String id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

Node.js/Express: Role-Checking Middleware

For Node.js applications, you can create a reusable middleware function that checks roles from the decoded JWT. This example assumes you are already verifying the JWT (using a library like jsonwebtoken or express-oauth2-jwt-bearer) and the decoded token is available on req.user.

/**
 * Middleware factory that requires a specific realm role.
 * Returns 403 Forbidden if the user does not have the role.
 */
function requireRole(role) {
  return (req, res, next) => {
    const roles = req.user?.realm_access?.roles || [];
    if (!roles.includes(role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

/**
 * Middleware factory that requires a specific client role.
 * @param {string} clientId - The Keycloak client ID
 * @param {string} role - The required client role
 */
function requireClientRole(clientId, role) {
  return (req, res, next) => {
    const clientRoles = req.user?.resource_access?.[clientId]?.roles || [];
    if (!clientRoles.includes(role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

// Usage examples
app.get('/api/users', requireRole('admin'), (req, res) => {
  // Only users with the 'admin' realm role can access this endpoint
  res.json(users);
});

app.get('/api/reports', requireClientRole('reporting-service', 'report-viewer'), (req, res) => {
  // Only users with the 'report-viewer' client role on 'reporting-service' can access
  res.json(reports);
});

app.delete('/api/users/:id', requireRole('admin'), (req, res) => {
  // Delete user logic
  res.status(204).send();
});

For a more complete setup including JWT verification, token refresh handling, and session management, refer to the Skycloak documentation.

Best Practices

Following these practices will help you maintain a clean, auditable, and scalable RBAC implementation.

Apply the Principle of Least Privilege

Assign users the minimum set of roles required to perform their job functions. Start with no roles and add permissions as needed, rather than starting with broad access and restricting later. Review and revoke roles when users change teams or responsibilities.

Use Groups for Role Assignment at Scale

Avoid assigning roles directly to individual users beyond the first few team members. Instead, create groups that mirror your organizational structure (e.g., engineering, support, billing) and map roles to those groups. This makes onboarding and offboarding a single group membership change rather than a series of individual role assignments.

Audit Role Assignments Regularly

Schedule periodic reviews of role assignments, especially for privileged roles like admin. Look for:

  • Users with roles they no longer need.
  • Roles that are assigned but never used.
  • Composite roles that have grown to include too many permissions.

Keycloak’s Admin Console provides a user list filtered by role, which helps with this review. You can also export role assignments via the Admin REST API for programmatic auditing.

Prefer Client Roles for Application-Specific Permissions

When a permission only makes sense within a single application, define it as a client role rather than a realm role. This keeps the realm role namespace clean and avoids confusion when different applications use the same role name with different semantics.

Document Your Role Hierarchy

Maintain documentation that describes each role, what it grants, and which composite roles include it. This is especially important when using composite roles, where the effective permissions of a user may not be obvious from their directly assigned roles alone.

Separate Development and Production Roles

Do not reuse the same role configuration across environments without review. Development environments often have permissive role assignments that would be inappropriate in production. Use Keycloak’s realm export/import functionality to move configurations between environments, and review role mappings as part of your deployment checklist.

Conclusion

Keycloak’s RBAC implementation provides the building blocks for authorization at any scale, from a handful of realm roles for a small team to a full Authorization Services deployment with composite policies for enterprise applications. The key is to start simple with realm roles and groups, then layer on client roles and authorization policies as your access control requirements grow.

The combination of group-based role assignment, JWT token mapping, and centralized policy evaluation means that your application code stays clean while Keycloak handles the complexity of who can access what.

Ready to deploy Keycloak with RBAC configured? Get started with Skycloak for a fully managed Keycloak instance with enterprise-grade role management out of the box.

Guilliano Molaire
Written by Guilliano Molaire Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman