tut: Build a custom Keycloak authentication flow - #395
Merged
Merged
Conversation
xgp
marked this pull request as ready for review
September 14, 2026 09:14
pnzrr
approved these changes
Sep 16, 2026
Building a flow with kcadm mutates a bound flow one call at a time, which is fine on a throwaway realm and wrong on one serving logins. Add a "Doing this safely in production" section naming the window that opens between calls, and point at the Apache 2.0 keycloak-atomic-auth-flows extension and its announcement post as the way to apply a whole flow tree in one transaction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GUJfhmq5sERGKP3o2tFcKs
xgp
force-pushed
the
content/T33-custom-authentication-flow
branch
from
September 17, 2026 13:11
8414016 to
407986d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Build a Custom Keycloak Authentication Flow
Cluster: D (concepts/how-to) · Queue item: T33 · Track: Authentication (new)
Primary keyword: keycloak custom authentication flow
Secondary: keycloak conditional authentication, keycloak conditional otp, keycloak authentication flow requirement, keycloak step up authentication flow
What this helps a reader do
Build and bind a working conditional authentication flow — users holding one role must
present a TOTP code, everyone else logs in with a password only, and SSO keeps working —
and then recognise the ways the requirement model fails without producing an error.
The official documentation explains what
REQUIRED,ALTERNATIVE,CONDITIONAL, andDISABLEDmean. It does not say what to set, in what order, or what happens when you get itwrong, and every one of those failures is silent: the flow saves, loads, and logs people in
while doing something other than what was intended. This page links the official reference
rather than restating it, and supplies the tested
kcadm.shsequence, the conditiondecision table, and the named failure modes.
Verified against
Keycloak 26.7.3 (
quay.io/keycloak/keycloak:26.7.3,start-dev, H2 dev database),in a container on the drafting machine. Every command, error string, and login result in the
page was produced by an actual run, and the full published command sequence was re-run
verbatim against a fresh realm at the end.
Measured results reproduced in the page:
execution=CONFIGURE_TOTP; non-role-holder → 0 prompts, straight tocode=.Browser - Conditional 2FAsubflow enabled next to a secondconditional 2FA subflow → 2 OTP prompts for the same user. Disabling it → 1.
formssubflow toREQUIREDat the top level stops theCookieauthenticator running, so the second app visit shows a login form instead of an
immediate
code=. Reverting restores SSO.CONDITIONALsubflow containing no condition execution is skipped entirely — theREQUIREDOTP form inside it never runs, and nothing is written to the server log.kcadmarriveDISABLED.kcadm update .../executions -n -s requirement=…sends a partial representation andKeycloak stores
priority: 0, moving the execution to the front of its level. The pageuses a read-modify-write helper instead; priorities were confirmed preserved.
It is illegal to add sub-flow to a built in flowandModelException: Cannot remove authentication flow, it is currently in use.The condition decision table is generated from
authentication/config-description/<id>on26.7.3, so the help text and config keys are the server's own.
Could not verify
<details>block was written from the REST behaviourand the 26.7.3 console layout, not from a click-through — this run had no browser.
conditional-level-of-authenticationandconditional-sub-flow-executedaredescribed from their server-supplied help text and config keys only; neither was exercised
in a login. They are named as pointers, and no behavioural claim is made about them.
run against a production database.
Structure notes
sidebars.tutorials.js— this is its firsttutorial, so the category lands with it rather than as an empty dead end.
tutorials/index.md.image:frontmatter key.Internal links added
/tutorials/getting-started/first-realm-client-user/(sibling)/tutorials/getting-started/run-keycloak-locally/(sibling)/tutorials/securing-applications/validating-tokens/(sibling)/docs/authentication/understanding-flows/(docs)/docs/authentication/complex-flows/(docs)/hosting/dedicated-clusters/,/support/,/extensions/via<ProductionNote />, whichis the only Phase Two mention in the page
Follow-ups for later PRs
the same conditional-subflow mechanics and neither exists on
mainyet.deliberately stops at naming
conditional-level-of-authenticationrather than covering it.docs/authentication/understanding-flows.mdcould gain a pointer back to this tutorial.Checklist
pnpm install --frozen-lockfile && pnpm buildpasses<ProductionNote />Rationale and queue state live in the private
content-marketingrepo.