Skip to main content

Keycloak LTS: the security backports nobody publishes

· 11 min read
GR Patil
Phase Two

Keycloak publishes releases and container images for the current minor version only. It does backport selected security fixes to the two most recent even-numbered branches, and it tags them — but it cuts no GitHub release and builds no image from those tags. As of today there are nine such tags on release/26.4 and three on release/26.6, containing fixes for CVEs that were announced months ago, that you cannot docker pull from anywhere upstream.

Phase Two now builds them. quay.io/phasetwo/keycloak:26.4.16 and quay.io/phasetwo/keycloak:26.6.7 exist today, built from the tag's own Dockerfile, and we intend to keep building the two previous minor lines alongside the current one for as long as upstream keeps backporting to them.

JWKS explained: rotation, caching, validating tokens

· 14 min read
Jeff Patzer
Phase Two

A JWKS — JSON Web Key Set — is a JSON document containing a list of public keys, each encoded as a JWK (JSON Web Key). Its purpose is to let anyone verifying a signed token fetch the right public key over HTTP instead of having it configured by hand. The token names the key it was signed with in its kid header; the verifier looks that kid up in the set.

That is the whole idea, and it buys one specific thing: the signer can change keys without anyone who verifies its tokens changing configuration. Everything else about JWKS — the field names, the caching, the rotation ordering — follows from that.

This post covers what is actually in a JWK, where the JWKS URL comes from, what Keycloak publishes and what it deliberately does not, and the two directions the traffic flows in. Every number and every error string below came from a real run.

Tested against

Keycloak 26.7.4 in a container, plus Python 3.12 with cryptography 46 for the key arithmetic. JWK field definitions are from RFC 7517 and RFC 7518.

Experimental: ship your Keycloak logs and events to your own OTLP endpoint

· 6 min read
GR Patil
Phase Two

We're shipping an experimental Telemetry Export for Enterprise Keycloak clusters. Point it at your own OTLP endpoint and your cluster's Keycloak logs and authentication events start arriving in whatever you already run — OpenSearch, Datadog, Grafana, SigNoz, Elastic, or your own OpenTelemetry Collector.

No agent to install, no log shipper to configure, and nothing to run on your side except the collector you already have.

Keycloak Clusters as Code: The Phase Two Management API, API Credentials and Terraform Provider

· 9 min read
GR Patil
Phase Two

Everything you can do in the Phase Two console, you can now do from code.

Create a dedicated Keycloak cluster. Add a realm to it. Attach a custom domain and watch the certificate get issued. Upload a custom provider. Restrict the admin console to your office IP range. Pull yesterday's logs.

Three things shipped together, because none of them is much use alone: the Management API, the API credentials that authenticate to it, and a Terraform provider generated from the same spec.

All three are experimental for now. The console marks API credentials as such, and the Terraform provider is at 0.1.0. Point them at test environments rather than production while the surface settles.

Keycloak 26.7.4: 6 CVEs, Two Unauthenticated DoS

· 6 min read
GR Patil
Phase Two

Bottom line: upgrade this week if your login page or SAML endpoints are reachable from the internet, or if you run stateless mode on MySQL/MariaDB. Otherwise take it in your normal cycle. Keycloak 26.7.4 fixes six CVEs — five published as high, one medium. Two of them let an unauthenticated attacker exhaust memory and crash the server by hitting endpoints that are open by definition. One breaking change, in Authorization Services URI matching.

Keycloak CORS errors: why your SPA gets blocked

· 10 min read
GR Patil
Phase Two

A Keycloak CORS error is almost never a CORS-configuration problem in the general sense. There is no CORS server setting to turn on. Keycloak decides per request by comparing the browser's Origin header against the Web Origins list on the OIDC client named in that request, using exact string matching. If it matches, the response carries Access-Control-Allow-Origin. If it does not, you get 403 with the body {"error":"Invalid origin"} — and the browser reports it as a CORS failure, which sends most people to the wrong place.

So the first thing to do is not to read a CORS guide. It is to open the Network tab, find the failing request, and check whether the status is 403 with that body. That single fact splits every cause below into two halves.

Keycloak Production Readiness Checklist

· 14 min read
Jeff Patzer
Phase Two

A Keycloak production readiness checklist has to answer two different questions, and most published ones only answer the first. Keycloak's start command refuses to boot until you settle two things, and it prints a clear error for each, so those are easy. The harder list is everything it will happily let you ship wrong: brute force protection is off, your audit log accepts forged IP addresses from anyone, event tables grow forever, and the readiness endpoint disagrees with your load balancer for the first few seconds of every restart.

Everything below was run against quay.io/keycloak/keycloak:26.7.3. Where a number appears, it came out of a terminal, not from memory.

Keycloak invalid_grant: the eight things it actually means

· 12 min read
Jeff Patzer
Phase Two

Keycloak returns invalid_grant for at least eight unrelated failures, and the error code itself tells you nothing. The useful field is error_description, which Keycloak fills in with a short string that maps almost one-to-one onto a cause:

{"error":"invalid_grant","error_description":"Code not valid"}

invalid_grant is OAuth's designated bucket for "the grant you presented is no good", so Keycloak uses it for expired codes, replayed codes, PKCE mismatches, rotated refresh tokens, dead sessions, revoked offline tokens, and bad passwords alike. Read the description, find it in the table below, stop guessing.

Everything here was run against Keycloak 26.7.3 on 2026-09-07, with realm defaults except where a test says otherwise.

Keycloak Skills and the Phase Two MCP Server

· 15 min read
Razvan Tufisi
Phase Two
GR Patil
Phase Two

Today we're launching keycloak-skills — an open-source Agent Skills plugin that teaches Claude how to configure Keycloak correctly — and the Phase Two Keycloak MCP server, 158 admin tools that let it do the work against a live cluster instead of just telling you what to type.

Two commands to install. Works against any Keycloak — and gets sharper the closer you get to ours. Don't have a Keycloak yet? The agent can provision one for you and it's free for 30 days.

Keycloak Custom Domains Can Now Serve App Association Files

· 5 min read
Jeff Patzer
Phase Two

Custom domains on Phase Two can now serve the files iOS and Android use to link a domain to a mobile app. Upload them from the dashboard and they are live in minutes — no deploy, no cluster restart.

That closes a gap that had nothing to do with Keycloak's capabilities and everything to do with where Keycloak sits in a mobile login flow.