Learn Keycloak - Fine-Grained Authorization
Episode 25 of 31

Learn Keycloak - Fine-Grained Authorization

Implementing fine-grained authorization with Keycloak's Authorization Services: resources and scopes, policies based on role, group, user, client, time, and JavaScript, plus the permission evaluation flow that produces an RPT.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 24 you secured the entrance: brute force protection, security headers, and token security. Episode 25 goes deeper — from who may sign in to what may be done after signing in. Authentication answers identity; authorization answers permission. Keycloak provides the Authorization Services module for managing access at the resource level, not just per role.

Authorization Services in Keycloak

Authorization Services is enabled per client via the Authorization tab on the client page. Once enabled, Keycloak becomes a policy decision point that evaluates every access request based on the resources, scopes, policies, and permissions you define.

This approach is resource-based: decisions are made per resource, considering the request context — who asks, from which IP, at what time, and what data is involved. This differs from classic RBAC, which only looks at the user's role label. With context-based decisions, two users with the same role can get different decisions because their time or location differs.

Several core concepts you'll use constantly:

ConceptRole
Resourcethe protected object, e.g. a document, API endpoint, or file
Scopethe action that can be performed on a resource: view, edit, delete
Policya logic rule: a specific role, a specific user, a specific time
Permissionthe binder between a resource and a policy
RPTthe token resulting from evaluation, carrying grants for resources

Keycloak implements UMA 2.0 as its foundation — a standard that lets resource owners govern who may access what, with a structured permission ticket flow.

Resources & Scopes

The first step is modeling what's protected. In the Authorization → Resources tab, you define resources with a name, type, URI, and attributes. Scopes describe the actions that can be performed:

Resource and scope definition
{
  "name": "Transaksi",
  "type": "urn:bank:transaction",
  "uris": ["/transactions/*"],
  "scopes": ["view", "edit", "delete"],
  "attributes": {
    "region": "jakarta"
  }
}

attributes are resource attributes — metadata a policy can use for context-based decisions. For example the region attribute can be the basis for a rule like "can only be edited from the same region". uris connect the resource to the protected API endpoints, so enforcement can be tied directly to request routes. Scopes can also be arranged as separate scope permissions so their usage is controlled per scope.

Policies

A policy is the decision logic. Keycloak provides many types that can be combined:

Policy TypeLogic
Role-basedallows holders of a specific role
User-basedallows specific users
Group-basedallows members of a specific group
Client-basedallows specific clients
Time-basedonly valid within a certain time range
JavaScriptlogic freely written in JavaScript
Aggregatedcombines several policies with AND or OR rules

Role-based policy is the most common: "role teller may view the Transaksi resource". Time-based is useful for working hours: "transfers only allowed from 08.00 to 17.00". JavaScript policy gives full flexibility — for example comparing a request attribute with a resource attribute directly. Aggregated policy combines them all: role teller AND working hours AND region jakarta. Client-based is useful in service-to-service scenarios, where access is determined by the calling application's identity, not just the user.

Permissions

A permission is the binder between a resource (or scope) and one or more policies. Keycloak recognizes two forms:

  • Resource permission — governs all access to a resource.
  • Scope permission — governs access to a specific scope within a resource.
Permission combining policies
{
  "name": "Teller boleh view transaksi",
  "type": "resource",
  "resources": ["Transaksi"],
  "scopes": ["view"],
  "policies": ["Hanya role teller", "Hanya jam kerja"]
}

Evaluation is AND across the policies within one permission: both policies above must pass before access is granted. This is the most common form of context-based decisions — the user's role is correct, but outside working hours it's still denied.

Permission Evaluation Flow

When an application requests access, the sequence is:

  1. Authorization request — the application sends an access request naming the resource and scope.
  2. Policy evaluation — Keycloak evaluates all policies bound to that permission.
  3. Permission ticket — in the UMA flow, if authorization isn't yet clear, a permission ticket is issued as a "needs authorization" marker.
  4. RPT — once the decision is approved, Keycloak issues an RPT carrying the grants.

The most common way to obtain an RPT is through the token endpoint with UMA ticket grant:

Obtaining an RPT via UMA ticket grant
curl -X POST "https://sso.example.com/realms/bank/protocol/openid-connect/token" \
  -H "Authorization: Bearer <access_token>" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  -d "client_id=bank-app" \
  -d "audience=bank-app" \
  --data-urlencode "permission=Transaksi#view"

The permission parameter is filled with a resource and scope combination separated by a hash, for example the resource Transaksi with the scope view. urn:ietf:params:oauth:grant-type:uma-ticket is a special grant type meaning "give me an RPT for this permission". Keycloak also provides an authorization request endpoint (/authz/authorize) and an entitlements endpoint for older patterns — retrieving all of a user's entitlements against a resource server at once — while modern flows run through the token endpoint.

Implementation: PEP & PDP

Architecturally, decision and enforcement are separated:

  • PEP (Policy Enforcement Point) — the layer in the application that intercepts requests, asks for decisions, and enforces the result. Keycloak provides a policy enforcer or adapters for popular languages.
  • PDP (Policy Decision Point) — Keycloak itself, which evaluates policies and issues decisions.

To protect an API, the PEP is installed at the gateway or inside the service. In microservices architectures, the recommended pattern: one central PDP, while every service installs a thin PEP — decisions stay centralized, enforcement spreads across many points.

Important

Don't place decision logic inside the application. Rules must live in Keycloak as the PDP so audit and policy changes are centralized. The PEP only asks for a decision and enforces it — it doesn't decide.

Closing

Episode 25 introduced fine-grained authorization: Authorization Services per client with the resource, scope, policy, and permission concepts; policies based on role, group, user, client, time, JavaScript, and aggregated; and the evaluation flow from authorization request to permission ticket and RPT. You also understood the PEP and PDP separation, plus implementation patterns for APIs and microservices.

Key takeaways:

  • Authorization Services is a centralized PDP — rules live in Keycloak, applications only enforce.
  • Resource + scope + policy + permission is a four-part model that binds together.
  • The RPT is proof of authorization — obtained via the token endpoint with UMA ticket grant.
  • UMA 2.0 gives control to the resource owner — the foundation for dynamic access models.

In the next episode (episode 26), you'll learn to manage clients at scale: client registration & dynamic clients — registering applications automatically via the API, using initial access tokens, and choosing the right client authentication method.

Learn Keycloak - Fine-Grained Authorization | Learn SSO with Keycloak