logo

Fine-grained authorization in Keycloak Explained

Introduction

Modern applications often require access control beyond simple role-based access control (RBAC). Keycloak addresses this need through its sophisticated fine-grained authorization services. Unlike static role checks, fine-grained authorization allows decisions to be made based on users, resources, scopes, attributes, context, or even runtime conditions such as time.

Keycloak’s authorization model is built upon UMA (User-Managed Access), a standard that enables resource-centric authorization. UMA allows a resource owner to securely control access to their assets—even when the protected resources are hosted on different systems. Using UMA principles, Keycloak enables applications to evaluate “who can do what on which resource” dynamically.

A Quick Overview of Permission Evaluation

Keycloak returns permissions through an artifact called the Requesting Party Token (RPT)—a JWT token that contains the evaluated access rights. There are three main ways to obtain authorization decisions:

  1. Explicit Permission Ticket Flow
  2. Direct Token Request Flow (RPT returned)
  3. Direct Token Request Flow returning decisions/permissions in JSON (no RPT)

Options 1 and 2 return an RPT token that the resource server needs to validate and interpret.
Option 3 bypasses JWT parsing and instead returns a plain JSON response representing decisions or permissions directly.

In this article, we primarily focus on Option 3, though we briefly outline the other two for context.

Option 1 – Explicit Permission Ticket Flow

This is the full UMA negotiation process and is needed only when permission requests must be dynamically raised per resource or per request.

Steps

  1. Resource server calls /authz/protection/permission -> gets permission ticket (Requires PAT – Protection API Token)
  2. Client then exchanges ticket at /protocol/openid-connect/token using grant_type=urn:ietf:params:oauth:grant-type:uma-ticket

Option 2- Directly Access Token Endpoint

Here we directly invoke with user access token as Bearer token

POST /protocol/openid-connect/token
grant_type=urn:ietf:params:oauth:grant-type:uma-ticket
audience=<resource-server-client-id>
Authorization: Bearer <user-access-token

This approach works best when:

✔ All resources and scopes already exist
✔ No dynamic resource creation or ad-hoc permission requests are required
✔ A single evaluation pass is enough
✔ User identity maps naturally from the bearer token

Keycloak returns an RPT token, which the application must decode and interpret.

Note: In the above also, we could optionally send permission parameter in the body.

Option 3 – Direct Token Request Returning Decisions or Permissions (JSON)

This is a simplified approach where the client does not receive an RPT token.
Instead, Keycloak responds with evaluation results directly:

Instead, Keycloak responds with evaluation results directly:

  • granted = true or response to indicate failure or
  • a list of identified permissions

For more details on authorization, please refer the Keycloak Authorization Services Guide.

Practical Example Use Case

According to Keycloak documentation:

“A permission associates the object being protected with the policies evaluated to determine whether access is granted.”

Permissions typically express a rule such as:

User X can perform action Y on resource Z

Where:

  • X → user, group, role, or contextual attribute
  • Y → read, update, approve, delete
  • Z → product, order, account, document, etc.

Let us define a business requirement:

A Supervisor (Bob) can update any order, but only within an allowed timeframe.

Pre-requisite:

A confidential client with Authorization Services Enabled

Step 1 — Create Resource

Navigate to:

Client → Authorization → Resources → Create

Fill values:

FieldValue
Nameorder_1
Typeorder
Display NameOrder
URI/orders/order_1

Note: If per-order rules exist, create order_1, order_2, etc.

Add scope update for this resource.

Step 2 — Create Policies

2.1 Supervisor Policy

Path:
Authorization → Policies → Create → Role-based

Values:

FieldValue
Namesupervisor-can-modify
Realm Rolesupervisor

This policy grants Bob supervisory privileges. He has the realm role supervisor initially assigned.

2.2 Time Policy

Path:
Authorization → Policies → Time Policy

Configure allowed time window.

Assume we call it:
allowed-time-policy

Note: By default, time policy evaluates realm timezone.

Step 3 — Create Permission

Path:
Authorization → Permissions → Scope-Based Permission

FieldValue
Nameupdate-order_1
Apply to Resource Typeorder
Scopeupdate
Policiessupervisor-can-modify, allowed-time-policy
Decision StrategyUnanimous

Decision Strategy: Unanimous → both policies must evaluate to TRUE.

Since we specified Apply to Resource Type as order, it applies permission to all resources of that type
Not just to order_1

Snippet of permission dialog

Expected Runtime Evaluation

Keycloak effectively executes:

IF (user has role SUPERVISOR)
   AND (current time is within allowed window)
THEN
      access = granted
ELSE
      access = denied

This becomes part of the JSON decision

Testing the Flow

Obtain user access token

  1. Obtain user access token
  2. Make request to token end point similar to following and the result will yield true if permission granted
```bash
curl -X POST "{{baseURL}}/realms/acmeauth/protocol/openid-connect/token" \
  -H "Authorization: Bearer <YOUR_BEARER_USER_TOKEN>" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  -d "permission=order_1#update" \
  -d "audience=orderauthservice" \
  -d "response_mode=decision" 
```

where, baseURL, points to Skycloak hostname

Summary

Keycloak authorization services enable precise access decisions—beyond static RBAC—using UMA-based policies. Among the three approaches described:

For REST-based microservices, Option 3 often yields the lowest overhead and cleanest design. Option – 1 is a requirement on special uses cases (more dynamic permission at runtime)

Skycloak provides production-ready managed Keycloak hosting, helping teams avoid the complexity of maintaining and scaling Keycloak themselves.

If you’re new to Skycloak, visit the Skycloak Getting Started Guide to learn more.


Leave a Comment

© 2025 All Rights Reserved. Made by Yasser