Keycloak as an AuthZEN Policy Decision Point

Guilliano Molaire Guilliano Molaire 9 min read

Yes, Keycloak can act as an AuthZEN Policy Decision Point. Keycloak 26.7.0, released in July 2026, added experimental support for the OpenID AuthZEN Authorization API 1.0, which lets an application ask Keycloak “can this subject perform this action on this resource?” over a small, vendor-neutral JSON API and get back a true or false decision. You turn it on with --features=authzen, and the decisions come from the resources, scopes, policies and permissions you already define in Keycloak Authorization Services. Keycloak 26.8.0, tagged on 1 October 2026, tightened one thing: the caller must now authenticate with a confidential client’s access token.

The rest of this post explains what AuthZEN is, why a standard decision API matters more than it first sounds, how the Keycloak implementation maps onto the policies you already have, and where the experimental label should make you careful.

What is AuthZEN?

AuthZEN is the OpenID Foundation’s standard API for asking an authorization engine for a decision. The specification, the OpenID AuthZEN Authorization API 1.0, defines how a Policy Enforcement Point (the code in your app or gateway that blocks or allows a request) talks to a Policy Decision Point (the service that evaluates policy and returns permit or deny). Keycloak’s own AuthZEN guide describes it as a protocol that lets applications “request authorization decisions without being tightly coupled to the internal details of the authorization engine.”

The two terms come from older access-control literature (NIST’s glossary has entries for both), and they are worth keeping straight because AuthZEN only standardises the conversation between them:

  • Policy Enforcement Point (PEP): the middleware, API gateway filter or MCP tool wrapper that intercepts a request and refuses it if the answer is deny.
  • Policy Decision Point (PDP): the engine that holds the rules and computes the answer. In this post, that is Keycloak.

A request names a subject (who), a resource (what), an action (which operation) and an optional context (anything else the policy needs, such as an IP address). The response is a JSON object with a boolean decision, and keeping the exchange that small is what lets the same request work against any compliant engine.

Why does a standard authorization API matter?

Before AuthZEN, every PDP had its own request format, so the enforcement code in your services was written against one vendor. Keycloak’s 26.7.0 release notes say this directly: applications that need fine-grained authorization “typically call Keycloak’s proprietary authorization API, coupling them to its internal model.”

In practice that coupling shows up in a few places. Services that call Keycloak Authorization Services today usually request a Requesting Party Token (RPT) through the UMA grant, then inspect the permissions inside it. If you later move some policies to Open Policy Agent, Cerbos or another engine, every one of those services needs new enforcement code. With AuthZEN, the PEP sends the same request shape to any compliant PDP, so swapping or splitting the decision engine becomes a configuration change at the PEP rather than a rewrite.

That is also why AuthZEN shows up in AI agent and MCP architectures. A tool gateway that guards dozens of tools should not need to know which engine evaluates each policy, so asking one standard question per call and acting on the boolean answer keeps the gateway simple.

If you are new to how Keycloak evaluates policies in the first place, our guide to fine-grained authorization in Keycloak and the overview of Keycloak Authorization Services policy types cover the model that AuthZEN sits on top of.

How do you enable AuthZEN in Keycloak?

You start Keycloak with the experimental feature flag. There is no extension to install.

bin/kc.sh start --features=authzen

“Experimental” has a specific meaning in Keycloak. The feature is listed as Type.EXPERIMENTAL in Keycloak’s Profile.java, its guide carries the experimental-feature banner, and experimental features sit outside the compatibility promises that apply to supported ones. The upgrade from 26.7 to 26.8 is a live example: the authentication rule for the endpoints changed between the two minor releases, which we cover below.

With the flag on, Keycloak publishes a discovery document per realm:

GET /realms/myrealm/.well-known/authzen-configuration
{
  "policy_decision_point": "https://keycloak.example.com/realms/myrealm",
  "access_evaluation_endpoint": "https://keycloak.example.com/realms/myrealm/authzen/access/v1/evaluation",
  "access_evaluations_endpoint": "https://keycloak.example.com/realms/myrealm/authzen/access/v1/evaluations"
}

A PEP can read that document once at startup and stop hard-coding endpoint paths.

What do you need to configure first?

AuthZEN does not add a new policy engine. It exposes Keycloak’s existing Authorization Services through the standard API, so the work you do in the admin console is the same work you would do for UMA. Keycloak’s AuthZEN guide lists four prerequisites:

  1. A client with authorization enabled. The client whose access token authenticates AuthZEN calls must have Authorization Enabled in its settings.
  2. Resources. The resource name in Keycloak maps to resource.id in the AuthZEN request, and the resource type maps to resource.type.
  3. Scopes. Scope names map to action.name. A read scope in Keycloak is the read action in AuthZEN.
  4. Policies and permissions that tie resources and scopes to decisions, using any of the policy types Keycloak already supports (role, group, user, client, time, JavaScript, aggregated and so on).

The mapping is an easy place to make a mistake, because it is natural to assume resource.id means the resource’s internal UUID, but it must match the resource name you typed in the admin console, and resource.type must match the type field on that resource.

How do you call the Evaluation API?

You send a POST with a bearer token and a JSON body. Since Keycloak 26.8.0, the upgrading guide states that the AuthZEN endpoints “require the caller to authenticate with a confidential client’s access token,” and that previously a user’s access token was also accepted. So the PEP first gets its own token with the client credentials grant:

TOKEN=$(curl -s -X POST 
  "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" 
  -d grant_type=client_credentials 
  -d client_id=orders-pep 
  -d client_secret="$PEP_SECRET" | jq -r .access_token)

Then it asks for a decision:

curl -s -X POST 
  "https://keycloak.example.com/realms/myrealm/authzen/access/v1/evaluation" 
  -H "Authorization: Bearer $TOKEN" 
  -H "Content-Type: application/json" 
  -H "X-Request-ID: req-abc-123" 
  -d '{
    "subject":  { "type": "user", "id": "username:alice" },
    "resource": { "type": "document", "id": "quarterly-report",
                  "properties": { "classification": "confidential" } },
    "action":   { "name": "read" },
    "context":  { "ip_address": "192.168.1.100" }
  }'
{ "decision": true }

A few details from the Keycloak guide are worth knowing before you build on this:

  • Subject lookup. subject.type is either user or client. For users, Keycloak treats a UUID as an internal user ID and anything else as a username, unless you use an explicit prefix: id:, username: or email:. The email: prefix returns 400 Bad Request if the realm allows duplicate emails, because the lookup would not be unique.
  • Unknown subjects are a deny, not an error. If the subject does not resolve to a user or client, you get HTTP 200 with {"decision": false}. Log these on the PEP side, because a typo in a subject ID looks exactly like a legitimate denial.
  • Client subjects are restricted. When subject.type is client, the subject.id must match the client_id the bearer token was issued to, otherwise the decision is false. In other words, a client can ask about itself, not about other clients.
  • Context reaches your policies. resource.properties and the top-level context are merged into the evaluation context, and subject.properties is merged into the subject’s identity attributes, so policies can use them.
  • Request tracing. Keycloak copies any X-Request-ID header from the request onto the response, including error responses, which makes PEP and PDP logs easy to join.

Can you batch authorization checks?

Yes. The Evaluations endpoint takes defaults at the top level and an evaluations array whose items override them, which suits a UI that needs to decide which of twenty buttons to show.

{
  "subject": { "type": "user", "id": "alice" },
  "action":  { "name": "read" },
  "options": { "evaluations_semantic": "deny_on_first_deny" },
  "evaluations": [
    { "resource": { "type": "document", "id": "public-doc" } },
    { "resource": { "type": "document", "id": "restricted-doc" } }
  ]
}

Keycloak supports three semantics. execute_all is the default and returns every decision. deny_on_first_deny stops at the first deny and marks it with "reason": "deny_on_first_deny" in the item’s context. permit_on_first_permit stops at the first permit, which fits “can the user do any of these?” checks.

When should you not use AuthZEN on Keycloak yet?

AuthZEN on Keycloak is a good fit for new enforcement points and for prototypes, and a poor fit for anything you cannot re-test on every minor upgrade. The 26.7 to 26.8 change from “any valid token” to “confidential client token only” is the kind of change experimental features are allowed to make, and a PEP that relied on forwarding the user’s own token would have started failing after the upgrade. We think that change was the right call from a security standpoint, since it stops end users from probing the PDP directly, but it is a reminder to pin the Keycloak version your PEPs were tested against.

There are also capability gaps compared with the UMA flow you may already use:

  • No permission tickets or resource sharing. If your product lets users share resources with each other through UMA, that stays on the UMA endpoints. Our UMA 2.0 resource sharing guide covers that model.
  • Decisions only, no token. UMA gives you an RPT that downstream services can verify offline. AuthZEN gives you a per-request decision, which means a network call to Keycloak on every check unless your PEP caches results.
  • Only the Evaluation APIs. Keycloak’s guide says it implements the Evaluation and Evaluations APIs. If you were hoping to use other parts of the AuthZEN family to list which resources a subject can reach, check the guide for your version before designing around them.

If what you actually need is policy-as-code in a separate engine, our post on Keycloak fine-grained permissions and OPA walks through that architecture, and AuthZEN is what lets you point the same PEP at either engine later.

What does running Keycloak as a policy decision point change in production?

Turning Keycloak into a PDP moves it onto the request path of your APIs, so its availability and latency now matter for every authorization check, not just at login. That is an operational decision as much as a design one. If you run Keycloak yourself, you own the feature flag, the upgrade testing for an experimental API and the capacity planning. Keycloak’s official sizing guidance is driven by request rate (it budgets one vCPU per 15 password logins per second, for example), but it publishes no figure for AuthZEN evaluations, so load-test your own policies at your expected call rate rather than estimating from user counts.

On Skycloak’s managed Keycloak you still design the resources, scopes and policies, while we operate the upstream Keycloak cluster. For the roles those policies usually build on, see our role-based access control overview. Teams evaluating attribute-based rules on top of this can also read our introduction to attribute-based access control.

Frequently asked questions

Is AuthZEN supported in Keycloak?

AuthZEN is an experimental feature in Keycloak. It was added in Keycloak 26.7.0 in July 2026 and is still listed as experimental in 26.8.0, enabled with --features=authzen. Experimental features can change between minor releases and are not covered by the compatibility guarantees that apply to supported features.

What is the difference between a PDP and a PEP?

A Policy Enforcement Point is the code that intercepts a request and blocks or allows it, such as an API gateway filter. A Policy Decision Point evaluates the rules and returns permit or deny. AuthZEN standardises the request and response between the two, so a PEP can talk to any compliant PDP, including Keycloak.

Does AuthZEN replace Keycloak UMA and Authorization Services?

No. AuthZEN in Keycloak is a standard front door to the same Authorization Services engine. You still define resources, scopes, policies and permissions on an authorization-enabled client. UMA remains the way to get Requesting Party Tokens and to support user-to-user resource sharing with permission tickets.

Which token do I use to call the Keycloak AuthZEN endpoints?

Since Keycloak 26.8.0, the AuthZEN endpoints require an access token issued to a confidential client, and the guide requires that client to have authorization enabled. A user’s access token was accepted in 26.7 but is rejected from 26.8 onward, so PEPs should use the client credentials grant.

Is AuthZEN useful for MCP servers and AI agents?

It can be. An MCP server or tool gateway can act as a PEP and ask Keycloak for a decision before running each tool call, with the tool as the resource and the operation as the action. Token audience validation still has to happen first, as covered in our MCP server audience post.

Sources

  • OpenID Foundation, OpenID AuthZEN Authorization API 1.0, https://openid.net/specs/authorization-api-1_0.html
  • Keycloak, “AuthZEN Authorization” guide (Securing Applications), https://www.keycloak.org/securing-apps/authzen-authorization, source at https://github.com/keycloak/keycloak/blob/26.8.0/docs/guides/securing-apps/authzen-authorization.adoc
  • Keycloak, 26.7.0 release notes, “Standardized authorization decisions with AuthZen (experimental)”, https://github.com/keycloak/keycloak/blob/26.7.0/docs/documentation/release_notes/topics/26_7_0.adoc
  • Keycloak, 26.8.0 upgrading guide, “AuthZEN changes”, https://github.com/keycloak/keycloak/blob/26.8.0/docs/documentation/upgrading/topics/changes/changes-26_8_0.adoc
  • Keycloak, “Concepts for sizing CPU and memory resources” (High Availability guide), source at https://github.com/keycloak/keycloak/blob/26.8.0/docs/guides/high-availability/partials/concepts/perf_recommendations.adoc
  • NIST CSRC Glossary, “policy decision point”, https://csrc.nist.gov/glossary/term/policy_decision_point

Somewhere to run this that stays patched

Everything above works the same on Skycloak, because it is real upstream Keycloak rather than a fork. What changes is who handles the upgrades, backups and security patches afterwards.

Guilliano Molaire
Written by
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.

Start Free Trial Talk to Sales
© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman