What Is an Authentication Flow in Keycloak?

What Is an Authentication Flow in Keycloak?

The complete, in-depth guide to the configurable decision tree Keycloak actually runs every time someone logs in — and how to reshape it for your own organization's needs.

Every earlier guide in this series has treated “the user logs in” as a single, almost invisible step — a black box that simply produces a logged-in session on success. It’s time to open that box. Picture an airport security checkpoint that isn’t actually one uniform line for every traveler. Frequent flyers with pre-approved trusted-traveler status glide through a fast lane with minimal screening. First-time international arrivals are routed through a longer sequence: passport check, customs declaration, sometimes a secondary interview. A crew member in uniform takes an entirely different, staff-only path altogether. One airport, one overall goal — confirm this person is who they claim to be and decide whether to let them through — but several distinct, carefully designed sequences of steps depending on who’s arriving. In Keycloak, that configurable sequence of steps a user is walked through during login is called an Authentication Flow.

This guide is a comprehensive, ground-up exploration of Authentication Flows: what they’re built from, the built-in flows Keycloak ships with, how the underlying decision logic actually evaluates step by step, how to safely customize a flow for your own organization’s needs, and the mistakes that have locked entire user bases out of applications when a flow was misconfigured. No prior identity or security background is assumed — every term is explained in full the moment it first appears.

1Core Concepts

Before touching the built-in flows or their internal mechanics, we need a precise definition of what an Authentication Flow actually is, in Keycloak’s own configuration sense.

What Is an Authentication Flow?

An Authentication Flow is a configurable, ordered sequence of steps — called executions — that Keycloak walks a user through in order to authenticate them for a particular purpose. It is not a single fixed algorithm baked permanently into Keycloak’s code; it’s a structure an administrator can inspect, rearrange, extend, and even completely replace through the admin console, without writing a single line of application code.

i
Configuration, Not Code

Earlier guides in this series described authentication as something that simply “happens.” An Authentication Flow is where that description gets specific: it’s the literal, editable configuration object inside Keycloak that determines exactly what “happening” means — which screens appear, in what order, and under what conditions, for a specific kind of login.

Executions: The Individual Steps

Each individual step inside a flow is called an execution. An execution is usually a specific authenticator — a piece of logic that performs one particular check, like “verify username and password,” “verify a one-time code,” or “check whether this device has been seen before.” A flow, at its simplest, is just an ordered list of these executions.

Everyday Analogy

Return to the airport checkpoint. Each individual station a traveler passes through — the document check, the metal detector, the customs declaration — is an “execution.” The overall sequence and arrangement of these stations, specific to which category of traveler is being processed, is the “flow.” Just as the airport can add a new station, remove one, or reorder them for a particular traveler category without rebuilding the terminal itself, an administrator can add, remove, or reorder executions inside a Keycloak flow without touching any application code.

Why Configurable Flows Exist at All

Different organizations have wildly different requirements for what counts as an acceptable login. A small internal tool might be satisfied with a plain password. A bank might insist on a password plus a one-time code, and only for logins from an unrecognized device. A healthcare portal might need to check that a user has accepted an updated consent form before finishing login. Rather than hardcoding one rigid login sequence and forcing every organization to live with it (or fork Keycloak’s source code to change it), Keycloak exposes the entire sequence as an editable structure — the Authentication Flow — so each organization can shape login to its own actual risk profile and regulatory needs.

Flows Are Scoped to a Realm

Like nearly everything else covered in this series, Authentication Flows live inside a specific Realm. Two separate Realms can have entirely different flows — one Realm’s employee login might require a hardware security key, while a completely separate customer-facing Realm on the very same Keycloak server might allow a simple password, because these two populations of users and their risk profiles are entirely distinct.

Distinguishing a Flow From What It Produces

It’s worth being precise about what a flow actually decides, versus what happens afterward. A flow’s job ends the moment it determines, definitively, whether this particular login attempt succeeded or failed. Everything covered elsewhere in this series about tokens, claims, and Roles happens only after a flow has already concluded successfully — the flow is exclusively concerned with the question “should this login be allowed to proceed at all,” never with what the resulting session or token subsequently contains.

A Flow Is Not the Same as a Single Login Page

A common early misunderstanding is picturing a flow as simply “the login page.” In reality, a single flow frequently spans several distinct screens shown one after another — a username-and-password form, followed by a one-time-code entry screen, possibly followed by a prompt to register a new second factor if none exists yet. Each of these separate screens corresponds to a distinct execution inside the same overall flow, not a separate flow in its own right.

Flows Also Cover What a User Sees Before Any Credential Is Entered

It’s worth noting that a flow’s first execution doesn’t always have to be a credential check at all. An organization offering multiple external identity providers alongside local login might place an Identity Provider Redirector execution first, presenting the user with a choice of login options before any password field ever appears. The flow, in this sense, governs the entire shape of the login journey from the very first screen a user sees through to the moment their identity is finally confirmed, not merely the credential-checking portion in isolation.

2Architecture & Components

A handful of building blocks combine to make a flow’s tree-like structure possible. Let’s name each one clearly before going further.
graph TD
    Flow["Authentication Flow
(e.g. 'browser')"] Flow --> E1["Execution: Cookie Check"] Flow --> E2["Execution: Identity Provider Redirector"] Flow --> SF["Sub-Flow: Forms"] SF --> E3["Execution: Username/Password Form"] SF --> CSF["Conditional Sub-Flow: OTP"] CSF --> C1["Condition: User has OTP configured"] CSF --> E4["Execution: OTP Form"]
Fig 2.1 — A simplified view of the built-in ‘browser’ flow’s tree structure: executions and a nested conditional sub-flow
Container

Authentication Flow

The top-level, named sequence of executions — the object an administrator creates, edits, and eventually binds to a purpose.

Step

Execution

One individual authenticator inside a flow, carrying out one specific check or action.

Nesting

Sub-Flow

A flow embedded inside another flow, letting related executions be grouped and governed together as a single logical unit.

Logic

Requirement Type

A per-execution setting (Required, Alternative, Disabled, or Conditional) controlling how that step affects the overall outcome — the entire subject of Chapter 4.

Binding

Flow Binding

The Realm-level setting connecting a specific flow to a specific purpose, such as “use this flow whenever someone logs in through a browser.”

Extensibility

Authenticator SPI

The plugin interface letting developers write entirely custom authenticator logic beyond Keycloak’s built-in set, covered in Chapter 10.

3The Built-In Flows

Keycloak ships with a set of ready-made flows covering the most common authentication purposes, before any administrator customizes anything.
FlowUsed For
BrowserStandard interactive logins where a user’s web browser is redirected to Keycloak’s own login page
Direct GrantLogins where an application collects the username and password itself and submits them directly to Keycloak, without redirecting the browser
RegistrationThe process a brand-new user goes through to create an account, when self-registration is enabled
Reset CredentialsThe “forgot my password” flow a user goes through to regain access to their account
First Broker LoginWhat happens the very first time a user logs in through an external identity provider (like “Sign in with Google”) linked to this Realm
ClientsHow Client Authentication itself (covered in depth elsewhere in this series) is evaluated
i
One Realm, Many Flows at Once

A single Realm doesn’t run just one Authentication Flow — it runs several simultaneously, each governing a different purpose. A user resetting their password is walked through the Reset Credentials flow, entirely separate from the Browser flow that governs their everyday login. Understanding which flow applies to which situation is essential before attempting to customize any of them.

Why the Browser Flow Gets the Most Attention

Among all the built-in flows, the Browser flow is overwhelmingly the one organizations spend the most time customizing, simply because it governs the everyday, highest-volume login path that the largest share of real users experience most often. The other flows matter and deserve their own review, but a security or user-experience initiative aimed at “how people log in” is, in the vast majority of cases, really an initiative aimed specifically at reshaping this one particular flow.

4Requirement Types: The Real Engine Behind Every Flow

This is the single most important concept for understanding how a flow actually behaves — and the one beginners most often get wrong.

Every execution inside a flow has one of four requirement types assigned to it, and this setting is what actually determines the flow’s real behavior, far more than the mere order of the steps:

Mandatory

Required

This step must succeed for the overall flow to succeed. If it fails, the entire login fails, full stop.

Either/Or

Alternative

At least one Alternative step among a set of siblings must succeed. If a Required step already exists at the same level, Alternative steps become effectively optional extra paths to success.

Skip

Disabled

This step is configured but entirely skipped — useful for temporarily turning a step off without deleting its configuration.

Sometimes

Conditional

Applies only to sub-flows: the sub-flow’s own contents are evaluated only if an attached condition (checked first) is met — covered fully in Chapter 7.

Everyday Analogy

Back at the airport: the passport check is Required — every single traveler must clear it, no exceptions. Choosing to declare goods verbally at the counter versus using the automated kiosk is Alternative — either path satisfies the same underlying requirement. A secondary interview room, entirely bypassed unless a risk flag was raised earlier, is Conditional. And a currently unstaffed inspection station, present on the floor plan but not actually operating today, is Disabled.

How Sibling Executions Combine

The requirement type of one execution only makes complete sense in the context of its siblings — the other executions at the very same level of the flow. A set of sibling executions marked Alternative means “succeed at any one of these,” while a Required step among the same siblings means “this one, no matter what, on top of whatever else succeeds.” Misreading how siblings combine is the single most common source of a flow behaving unexpectedly.

A Worked Example of Combination Logic

Consider a top level containing exactly three executions: a Required username/password form, and two Alternative options — an OTP form and a WebAuthn security-key check — both siblings of each other but not of the password form. Reading this correctly: the password form must succeed, full stop, no way around it. Then, separately, the user must succeed at either the OTP form or the security-key check, but never both and never neither. Change that OTP form’s requirement type from Alternative to Required, and the meaning shifts entirely — now every single user must pass both the password form and the OTP form, and the WebAuthn option becomes an entirely unreachable, dead configuration that no login path ever actually uses.

Disabled Steps Are Not the Same as Deleted Steps

It’s worth dwelling on the Disabled requirement type specifically, since it’s easy to underestimate. A Disabled execution remains fully configured — its settings, its position in the flow, any attached conditions — but Keycloak simply skips over it entirely during evaluation, as though it were never placed in the flow at all. This is genuinely useful for temporarily turning off a step (during an incident, or while troubleshooting) without losing the work of having configured it, and then flipping it back on later with nothing to reconfigure from scratch.

5Internal Working: Evaluating a Flow Step by Step

Let’s trace exactly what Keycloak does internally, in order, when a real user logs in through the standard Browser flow.
1

Flow Identified

Keycloak determines which flow applies to this specific login attempt, based on the flow bindings configured for the Realm (covered in Chapter 8).

2

Top-Level Executions Walked in Order

Keycloak processes the flow’s top-level executions and sub-flows in the order they’re configured, evaluating each according to its requirement type.

3

Required Steps Executed Unconditionally

Any Required execution runs and must succeed; a failure here immediately fails the whole login attempt, regardless of what else is configured.

4

Conditional Sub-Flows Checked First

Before running the contents of a Conditional sub-flow, Keycloak first evaluates its attached condition. If the condition isn’t met, the entire sub-flow (and everything nested inside it) is skipped entirely.

5

Alternative Paths Attempted

Among a set of Alternative siblings, Keycloak presents (or attempts) them until one succeeds, satisfying that portion of the flow.

6

Flow-Level Outcome Determined

Once every top-level execution and sub-flow has been resolved, Keycloak determines whether the overall flow succeeded, based on the combination of Required successes and at least one satisfied Alternative group at each level.

7

Login Completed or Rejected

On overall success, the login proceeds — token issuance follows exactly as described in earlier guides. On failure, the user sees an appropriate error and the login attempt stops.

6Sub-Flows and Branching Logic

Real-world login requirements are rarely a single flat list — sub-flows let a flow express genuine branching logic.

Why a Flat List Isn’t Enough

Consider a Realm that wants to offer two entirely different second factors — an authenticator app or a hardware security key — where a user only needs to succeed at one of them, but that whole “second factor” concept should itself only apply if the user has actually enrolled in either. Expressing this cleanly requires nesting: a Conditional sub-flow (only entered if the user has some second factor configured) containing two Alternative executions (either of which is acceptable) inside it.

graph TD
    Root["Browser Flow"]
    Root --> Req1["Required: Username/Password Form"]
    Root --> Cond["Conditional Sub-Flow:
Second Factor Required?"] Cond --> Check["Condition: User Has
OTP or Security Key Configured"] Cond --> Alt1["Alternative: OTP Form"] Cond --> Alt2["Alternative: Security Key (WebAuthn)"]
Fig 6.1 — A Conditional sub-flow containing two Alternative executions, expressing “if enrolled, succeed at either factor”

Sub-Flows Can Nest Further

A sub-flow can itself contain another sub-flow, allowing genuinely sophisticated decision trees — though, as with composite Roles discussed elsewhere in this series, nesting several layers deep makes a flow considerably harder for an administrator to reason about at a glance. Depth should be used deliberately, not accumulated by accident over successive edits.

Sub-Flows Without a Condition

Not every sub-flow needs to be Conditional. A plain sub-flow, given a Required or Alternative type of its own, is simply a way of grouping several executions together and treating that entire group as a single unit for the purposes of the parent flow’s own combination logic. This is useful purely for organizational clarity — bundling, say, every step related to “second factor entry” together under one labeled group — even when no conditional branching is actually involved.

Reading a Flow Diagram Correctly

When reviewing a flow in the admin console, indentation in the visual tree corresponds directly to nesting depth, and the requirement type shown alongside each row applies to that row relative to its own immediate siblings — not to the flow as a whole. A newcomer reading a complex flow for the first time should always ask, for any given execution, “who exactly are this row’s siblings, and what’s required among them?” rather than trying to judge overall strictness from position or indentation alone.

7Conditional Authenticators: Making Flows Context-Aware

Conditional sub-flows are where Authentication Flows stop being a static checklist and start reacting to who, exactly, is logging in.

What a Condition Actually Checks

A condition attached to a sub-flow is itself a small piece of logic evaluating something about the current login attempt — common built-in conditions check things like whether the user carries a specific Realm Role, whether a specific user attribute is set to a certain value, or whether the requesting Client matches certain criteria. If the condition’s check passes, the sub-flow’s contents run as normal; if not, they’re skipped entirely, as if they weren’t part of the flow at all for this particular login.

Everyday Analogy

A conditional sub-flow is like the secondary interview room at that airport checkpoint from Chapter 1 — most travelers walk straight past its door because the entry condition (a risk flag raised earlier in their specific case) was never triggered for them. The room, and everything inside it, remains entirely irrelevant to their particular journey through the checkpoint, without being physically removed from the building.

The Classic Use Case: Risk-Based Step-Up Authentication

One of the most common real-world patterns built on this mechanism is requiring a stronger second factor only for users holding a sensitive Realm Role (like “admin” or “finance-approver”), while ordinary users continue through a lighter-weight path. This is achieved entirely through a Conditional sub-flow checking Role membership — no application code changes needed, since the decision lives entirely inside the flow’s own configuration.

Production Example: Tiered Enforcement by Role

A company running an internal financial reporting tool commonly configures its Browser flow so that users holding the “finance-approver” Realm Role are routed through a Conditional sub-flow enforcing OTP, while every other employee logging into the very same application is not. This lets a security team apply a stronger control precisely where the risk actually concentrates, without burdening the entire user base with the same requirement uniformly.

Conditions Can Also Look at the Client or the Request Itself

Role and attribute checks are the most commonly used conditions, but they’re not the only ones available. A condition can also examine which specific Client initiated the login, letting an organization apply a stricter flow only when a particularly sensitive application is the one being logged into, even for a user who might face a lighter path when logging into a different, lower-risk application within the very same Realm. This lets the same underlying user population face different effective requirements depending on what they’re actually trying to access, not just who they are.

Conditions Are Evaluated Before Their Sub-Flow’s Contents, Never After

It’s worth being explicit about ordering here, since it matters for correctness: a condition is always checked first, before any execution nested inside its sub-flow runs. There is no way for something happening inside the sub-flow to retroactively change whether that sub-flow was entered in the first place — the decision to branch is made once, upfront, based only on information already available at that point in the login.

8Data Flow & Lifecycle

A flow isn’t designed once and forgotten — it moves through its own lifecycle as an organization’s requirements evolve.

Design. An administrator maps out the desired sequence of steps and branching logic, typically starting from a copy of a built-in flow rather than an entirely blank one, as covered in Chapter 9.

Binding. The finished flow is connected to a specific purpose at the Realm level — for example, designating a custom flow as the Realm’s active Browser flow, replacing the built-in default for that purpose.

Active Use. Every subsequent login of that type is evaluated against the bound flow, exactly as walked through in Chapter 5.

Testing After Changes. Any edit to a flow that’s actively bound takes effect immediately for the next login attempt — there is no separate “publish” step, which makes careful testing before binding a change to production especially important.

Iteration. As requirements change — a new second factor is adopted, a regulatory requirement shifts, a conditional check needs refining — the flow is edited and, if the change is significant, tested against a copy before being rebound.

graph LR
    A["Flow Designed
(often copied from a built-in flow)"] --> B["Tested
(ideally in a non-production Realm)"] B --> C["Bound to a Purpose
(e.g. set as the Browser flow)"] C --> D["Active on Every
Matching Login"] D --> E{"Requirements Change?"} E -->|"Yes"| F["Flow Edited"] F --> B
Fig 8.1 — The lifecycle of an Authentication Flow, from design through binding to ongoing iteration

9Customizing Flows: The Copy-Then-Modify Pattern

Almost every real-world customization follows the same safe, well-established starting pattern.

Why Not Edit the Built-In Flow Directly?

Keycloak’s built-in flows are typically protected from direct editing, and even where direct editing is technically possible, doing so is strongly discouraged. Built-in flows serve as a known-good baseline and, in some upgrade scenarios, may be reset or updated by Keycloak itself, potentially discarding direct edits.

The Standard Pattern

The overwhelming majority of real customizations follow the same three-step pattern: duplicate the relevant built-in flow under a new name, make the desired changes to executions and requirement types on that copy, and then bind that new, customized flow to the Realm in place of the original built-in one. This preserves the original as an untouched reference point that can always be restored by simply re-binding back to it.

!
Test Before Binding to Production

Because binding a flow change takes effect immediately with no staging step, a broken custom flow bound directly to a production Realm’s Browser flow can lock out every single user attempting to log in. Testing a new flow thoroughly in a non-production Realm — or at minimum, verifying it carefully with a test account before broad rollout — is essential.

Production Example: Adding Enterprise SSO Alongside Local Login

A company adopting a “Sign in with Corporate SSO” option alongside existing username/password login typically copies the default Browser flow, adds an Identity Provider Redirector execution as an Alternative alongside the existing password form, and binds the resulting copy as the Realm’s active Browser flow — giving users a choice between two paths that both lead to a successfully authenticated session.

What “Binding” Actually Means in Practice

A finished, customized flow accomplishes nothing on its own until it’s connected to a purpose through the Realm’s flow bindings — a small set of Realm-level settings, each naming which flow currently serves as, for example, “the Browser flow” or “the Direct Grant flow” for that Realm. Multiple customized flows can exist side by side inside the same Realm at once, sitting unused, and this is a deliberate, safe way to prepare a replacement in advance: build and thoroughly review the new flow first, and only flip the binding over once it’s fully ready, keeping the previous flow intact and instantly available to roll back to.

Rolling Back a Bad Change Quickly

Precisely because the original built-in flow is left untouched under the copy-then-modify pattern, recovering from a bad customization is usually as simple as re-pointing the relevant flow binding back to the original, restoring the previous, known-working behavior for every user immediately. This rollback path is one of the strongest practical reasons the copy-then-modify pattern is treated as close to mandatory rather than merely a suggestion.

Naming Conventions Matter More Than They Seem

As an organization accumulates several customized flows and sub-flows over time — one for standard employees, one for elevated-privilege accounts, one mid-rollout of a new second factor — clear, descriptive names for each become essential. A flow named simply “browser copy” tells a future administrator nothing about its purpose six months later, whereas a name like “browser – finance-approver-otp-enforced” communicates its intent at a glance, without needing to open and trace through the flow itself just to understand what it’s for.

10Building Custom Authenticators

When Keycloak’s built-in executions can’t express a genuinely custom check, developers can extend the system directly.

The Authenticator SPI

Keycloak exposes a Service Provider Interface (SPI) specifically for authentication, letting developers implement a completely custom authenticator — a new kind of execution — with its own logic, its own configuration options, and its own screen if it needs to interact with the user. Once installed on the server, a custom authenticator appears in the admin console’s execution list exactly like any built-in one, ready to be dragged into a flow at whatever position and requirement type an administrator chooses.

Production Example: Custom Device Reputation Check

A consumer platform wanting to silently check whether a login is coming from a device with a poor reputation (based on a proprietary internal risk score) commonly builds a custom authenticator that performs this check invisibly, without ever showing the user a screen, and routes the outcome into a Conditional sub-flow that only demands a stronger second factor when the device’s reputation score crosses a defined threshold.

Because a custom authenticator runs directly inside the login pipeline for every affected user, it deserves the same careful review, testing, and monitoring as any other security-critical code — a subtle bug here can either wrongly lock out legitimate users or, in the worst case, be tricked into letting an illegitimate login through.

When a Custom Authenticator Is (and Isn’t) the Right Call

Reaching for a custom authenticator is appropriate when a genuinely organization-specific check has no equivalent among Keycloak’s built-in executions and conditions — a proprietary risk score, an integration with an internal fraud-detection system, a check against a legacy identity store that predates the Keycloak rollout. It is usually the wrong call when the same outcome can be achieved by combining existing built-in conditions and executions in a Conditional sub-flow, since configuration changes carry far less ongoing maintenance burden than custom code that needs to be kept compatible with future Keycloak upgrades.

Deployment and Upgrade Considerations

A custom authenticator is deployed as a piece of installed server-side code, not a database record like a flow’s configuration, which means upgrading Keycloak itself can occasionally require revisiting a custom authenticator’s compatibility with the new version. Organizations that build custom authenticators typically track this as an explicit line item in their upgrade planning, rather than assuming configuration-only changes (like flow edits) and code-level extensions (like custom authenticators) carry the same upgrade risk.

11Advantages, Disadvantages & Trade-offs

Configurable flows are powerful, but that power comes with real complexity that deserves an honest accounting.

Advantages

  • Lets an organization tailor its login experience precisely to its own risk profile and regulatory requirements, without writing or maintaining application code
  • Conditional logic enables genuinely risk-based, context-aware authentication — stronger checks exactly where they’re actually needed
  • The copy-then-modify pattern keeps built-in flows available as a safe, known-good fallback
  • The Authenticator SPI allows unlimited extensibility for organization-specific checks that no built-in authenticator anticipates
  • A single Keycloak deployment can serve many populations (employees, customers, partners) with entirely different login requirements, each expressed as its own flow, without standing up separate identity infrastructure for each one

Disadvantages & Trade-offs

  • Deeply nested sub-flows with many Conditional and Alternative branches become genuinely difficult to reason about and audit
  • A misconfigured Required execution can lock out an entire user base immediately, with no staged rollout to catch the mistake first
  • Custom authenticators built on the SPI require real software engineering discipline — testing, code review, monitoring — not just configuration
  • Understanding exactly why a specific login succeeded or failed can require tracing through several nested levels of a complex flow
  • The lack of a built-in staging or approval step for flow changes places the entire burden of catching a mistake before it affects real users on the administrator’s own testing discipline

12Security

Because a flow governs every single login, its design carries direct and significant security weight.

Required vs. Alternative Is a Security-Critical Distinction

An administrator intending to mandate a second factor for every user, but accidentally configuring the OTP execution as Alternative rather than Required alongside the password form, has not actually enforced anything — a user can simply succeed via whichever Alternative path is easiest, silently skipping the intended second factor entirely. This exact class of misconfiguration has caused real-world incidents where an organization believed it had mandatory MFA in place when it did not.

ADR-010: Believing a Flow Enforces MFA Without Verifying It Anti-pattern Warning
Problem

A security team declares that multi-factor authentication is “enabled” in Keycloak, based on the presence of an OTP execution somewhere in the flow, without checking its actual requirement type or its position relative to sibling executions.

Why It Fails

Presence alone proves nothing about enforcement. An OTP execution configured as Alternative, or nested inside a Conditional sub-flow whose condition rarely triggers, can leave the overwhelming majority of real logins never actually reaching a second factor check at all.

Correct Approach

Verify enforcement directly by testing with a real account: attempt to log in and confirm the second factor is genuinely required, not merely offered. Periodically re-verify this after any flow edit, since a seemingly unrelated change elsewhere in the same flow can shift how sibling requirement types combine.

Locking Yourself Out

A poorly tested Required execution, or a custom authenticator with a bug, can render every single account in a Realm unable to log in — including administrator accounts needed to fix the very flow causing the problem. Maintaining a separate, carefully protected recovery path (such as a break-glass administrator account outside the affected flow, or documented server-level recovery steps) is a genuine operational necessity, not an optional precaution.

Conditions Are Only as Trustworthy as What They Check

A Conditional sub-flow that bases a security-relevant decision on a user attribute deserves scrutiny over who can actually set or change that attribute’s value. If an ordinary user could freely edit an attribute that a condition treats as a signal for “this user doesn’t need a second factor,” the condition becomes a self-service way to opt out of a control the organization intended to be mandatory. Security-relevant conditions should generally rely on Roles and attributes that only an administrator (or a trusted, separately audited process) can set — never anything an end user can adjust about their own account.

The First Broker Login Flow Deserves Its Own Scrutiny

Because the First Broker Login flow governs what happens the very first time a user arrives through an external identity provider, it often includes logic deciding whether to automatically link that external identity to an existing local account matching the same email address. Misconfiguring this specific flow has, in real incidents elsewhere in the industry, allowed an attacker who controls an email address to link into and take over an existing account under that same address at a different, unrelated identity provider — a reminder that this particular flow deserves as much careful review as the everyday Browser flow, even though it’s exercised far less frequently.

The Direct Grant Flow Carries Its Own Distinct Risk

Because the Direct Grant flow collects a username and password directly inside an application’s own form, rather than redirecting to Keycloak’s dedicated login page, it inherently cannot include any execution that needs to show the user an interactive, Keycloak-hosted screen mid-flow — a security-key prompt or a redirect to an external identity provider simply has nowhere to render inside this particular flow’s model. Organizations relying on Direct Grant for any user-facing login (as opposed to purely backend, machine-to-machine use) should recognize this ceiling explicitly, since it constrains which second factors can realistically be enforced there compared to the considerably more flexible Browser flow.

Reviewing Flows as Part of a Broader Security Audit

A periodic security review of an organization’s Keycloak deployment should treat Authentication Flow configuration as its own distinct checklist item, separate from reviewing Roles, Clients, or Required Actions. Because a flow’s real behavior depends on the interplay between step order, requirement types, and nested conditions, a reviewer benefits from actually testing a representative login for each meaningfully different user population — not merely reading the configuration and assuming its intent matches its actual, evaluated behavior.

13Monitoring, Logging & Metrics

Because a flow sits directly in the critical path of every login, its behavior deserves close, ongoing observability.
Reliability

Per-Step Success Rate

Tracking how often each individual execution succeeds or fails helps pinpoint exactly which step in a complex flow is causing user friction or outright failures.

Security

Conditional Branch Frequency

Monitoring how often a Conditional sub-flow’s condition actually triggers confirms whether risk-based logic is firing as intended, or silently never activating due to a misconfigured condition.

Change Management

Flow Edit Audit Trail

Logging every change made to a flow — who edited it, what changed, when it was rebound — is essential for both security review and diagnosing a sudden shift in login behavior.

Support

Abandonment Points

Identifying the specific step where users most often abandon a login attempt highlights friction that may need addressing through flow redesign or better user guidance.

Correlating Flow Behavior With Support Volume

A practical, easily overlooked metric is simply correlating spikes in login-related support tickets with recent flow changes. Because a flow edit takes effect immediately, a support-ticket spike beginning shortly after a specific change is a strong, fast signal pointing directly at the likely cause — often faster to notice through this correlation than through detailed per-execution metrics alone, especially in smaller organizations without a dedicated identity engineering team.

Watching for Unexpected Alternative-Path Usage

When a flow offers multiple Alternative paths (say, password login alongside SSO), tracking the relative volume flowing through each path over time can reveal whether an intended migration (like the passwordless rollout described in Chapter 15) is actually progressing, or whether users are quietly sticking with a legacy path far longer than expected, signaling a need for clearer in-product guidance nudging them toward the newer option.

14Design Patterns & Anti-patterns

Certain habits consistently produce flows that stay maintainable for years — and certain habits reliably produce a tangled, unauditable mess.

Good Patterns

  • Copy-then-modify: always start a custom flow from a duplicated built-in flow, never editing built-ins directly
  • Shallow, well-documented nesting: use sub-flows deliberately, and document what each Conditional branch is meant to achieve
  • Test in a non-production Realm first: especially for any Required execution change that could affect every user
  • Maintain a break-glass recovery path: a way to regain administrative access that sits outside whatever flow is being changed

Anti-patterns to Avoid

Common Mistakes

  • Editing a built-in flow directly instead of working from a copy
  • Assuming a security execution is enforced just because it appears somewhere in the flow, without verifying its requirement type
  • Binding an untested flow change directly to a production Realm’s Browser flow
  • Building deeply nested Conditional logic with no documentation of what each branch is for, until nobody on the team can explain the flow’s actual behavior anymore
  • Deploying a custom authenticator built on the SPI without the same code review rigor applied to any other security-critical component

15Real-World & Industry Examples

Customized Authentication Flows are the quiet engine behind a huge range of login experiences people encounter daily.

Banking Applications with Step-Up Authentication

Many banking platforms configure a Conditional sub-flow that demands an additional verification step specifically for high-risk actions or logins from unrecognized devices, while routine logins from a recognized device proceed through a lighter path — a direct, practical application of the risk-based pattern covered in Chapter 7.

Enterprises Migrating to Passwordless Login

Organizations rolling out passwordless authentication (via security keys or authenticator apps) commonly build a custom Browser flow offering the new passwordless option as an Alternative alongside the legacy password form during a transition period, later removing the password path entirely once adoption is complete — an incremental migration made possible entirely through flow configuration.

Healthcare Platforms Enforcing Consent Checks

A healthcare portal needing to confirm a patient has accepted an updated privacy notice before completing login can implement this as a custom Required execution inserted into the Browser flow, ensuring no session is ever established without that confirmation, regardless of which other login path the patient used to get there.

Consumer Platforms Blending Social and Local Login

A retail website offering both “Sign in with Google” and a traditional email/password option runs both as Alternative executions inside a single customized Browser flow, letting customers freely choose whichever path they originally used to create their account.

Educational Institutions Separating Student and Staff Requirements

A university running one Realm for its entire community frequently uses a Conditional sub-flow keyed to a “faculty” or “staff” Realm Role, requiring a stronger institutional security-key check for staff (who may handle sensitive student records) while students logging into the very same course portal proceed through a lighter password-and-OTP path — one flow, two effective experiences, shaped entirely by who is logging in.

SaaS Platforms Offering Customer-Configurable Security Policies

Some larger software-as-a-service platforms let their own enterprise customers choose their preferred second-factor policy from within the product itself, and translate that customer-level choice into a Conditional sub-flow keyed off a custom attribute recording which policy that customer’s organization selected — letting a single shared Realm serve many customer organizations, each with its own effective authentication requirements, without needing a separate Realm per customer.

16Frequently Asked Questions

Q1Is an Authentication Flow the same thing as a Required Action?
No — a Required Action (covered elsewhere in this series) is a task forced on a specific user after successful authentication but before login fully completes. An Authentication Flow is the broader sequence of authentication steps itself, evaluated for every login of a given type.
Q2Can I edit a built-in flow directly?
It’s technically possible in some cases, but strongly discouraged. The standard, safe pattern is to duplicate the built-in flow and customize the copy, preserving the original as an untouched fallback.
Q3What’s the difference between Required and Alternative, in one sentence?
A Required execution must succeed no matter what else happens; an Alternative execution is one of several acceptable paths where only one among its siblings needs to succeed.
Q4How do I make a second factor mandatory only for certain users?
Wrap the second-factor execution inside a Conditional sub-flow whose condition checks for the relevant Role, attribute, or other criteria — the sub-flow’s contents then apply only to logins meeting that condition.
Q5Does changing a bound flow take effect immediately?
Yes — there is no separate publish or staging step. Any edit to an actively bound flow applies to the very next login attempt, which is exactly why testing changes in a non-production Realm first is so important.
Q6What happens if I misconfigure a flow and lock everyone out?
This is precisely why maintaining a separate recovery path — a break-glass administrator account or a documented server-level recovery procedure outside the affected flow — is an essential precaution before making significant flow changes.
Q7Can I build my own completely custom authentication step?
Yes — through the Authenticator SPI, developers can implement entirely custom authenticator logic, which then appears in the admin console alongside built-in options, ready to be added to any flow.
Q8Do different Realms need the same Authentication Flow configuration?
No — each Realm has its own independent set of flows. Two Realms on the same Keycloak server can enforce completely different login requirements, tailored to each population’s own risk profile.
Q9Can one Realm have more than one customized version of the same flow type at once?
Yes — an administrator can build and save several customized flows side by side, but only one can actually be bound as the Realm’s active flow for a given purpose at any moment. The others simply sit ready, unused, until a binding is switched to point at them.
Q10Should security-relevant conditions be based on attributes a user can edit themselves?
No — a condition that decides something security-sensitive, like whether a second factor is required, should be based on Roles or attributes only an administrator or a trusted process controls, never something the end user can freely change about their own account.
Q11How can I quickly recover if a new flow breaks logins for everyone?
Because the original built-in or previously working flow is left untouched under the copy-then-modify pattern, simply switching the Realm’s flow binding back to that earlier flow restores working logins immediately, without needing to fix the broken customization under pressure first.

17Summary and Key Takeaways

“A password field is one screen. An Authentication Flow is the entire decision tree deciding which screens a user even sees.”

Key Takeaways

  • An Authentication Flow is a configurable, ordered sequence of executions that Keycloak walks a user through to authenticate them for a specific purpose, entirely editable through the admin console.
  • Keycloak ships several built-in flows — Browser, Direct Grant, Registration, Reset Credentials, First Broker Login, and Clients — each governing a different login purpose.
  • Every execution carries a requirement type — Required, Alternative, Disabled, or Conditional — and this setting, not just step order, determines the flow’s real behavior.
  • Conditional sub-flows make flows context-aware, enabling risk-based, step-up authentication without any application code changes — the same underlying mechanism that lets one Realm serve employees, students, or many different customer organizations with entirely different effective requirements.
  • The safe customization pattern is always copy the built-in flow, modify the copy, then bind it — never edit a built-in flow directly.
  • A misconfigured Required execution, or confusing Alternative with genuine enforcement, can either lock out an entire user base or silently fail to enforce a control the organization believed was mandatory.
  • The Authenticator SPI allows fully custom authentication logic when built-in executions can’t express an organization’s specific need — but demands the same engineering rigor as any other security-critical code.