What Is a Custom Required Action in Keycloak?

What Is a Custom Required Action in Keycloak?

The complete, in-depth guide to building your own mandatory step into Keycloak's login journey — from interface to production rollout.

Picture an airport security checkpoint that, for a specific traveler, occasionally adds one extra, mandatory step — a random secondary screening, a request to update an expired document on file — inserted into the ordinary process at exactly the right moment, blocking that one traveler from proceeding until it’s satisfied, while leaving everyone else’s path through the checkpoint completely untouched. An earlier guide in this series introduced Keycloak’s built-in Required Actions — verify email, update password, configure two-factor authentication — as exactly this kind of targeted, mandatory checkpoint step. This guide covers what happens when none of Keycloak’s built-in Required Actions fit an organization’s actual need, and a team has to build its own: a Custom Required Action.

This guide is a comprehensive, advanced-level exploration of building a Custom Required Action from the ground up: the exact interface it implements, how Keycloak decides when to trigger it, the multi-step interaction pattern it follows, how it’s packaged and deployed using the SPI discipline covered in this series’ packaging guide, and the real, production-tested patterns for building a custom mandatory step that’s both genuinely useful and safe to maintain over time. This guide assumes familiarity with Keycloak’s built-in Required Actions at a conceptual level and with the general SPI packaging and deployment discipline covered elsewhere in this series, and focuses specifically on the advanced mechanics of building a custom one.

1Core Concepts

Before implementing anything, let’s establish a precise definition of what a Custom Required Action actually is, and how it differs from Keycloak’s built-in ones.

What a Required Action Is, Restated Precisely

A Required Action is a mandatory step inserted into a user’s login journey, which must be completed before that login is allowed to finish — Keycloak ships with several built-in ones (verify email, update password, configure OTP) covered in this series’ earlier, beginner-level guide.

What Makes a Required Action “Custom”

A Custom Required Action is one an organization builds itself, implementing Keycloak’s own Required Action SPI, to enforce a mandatory step that has no equivalent among the built-in options — accepting an updated terms-of-service document, completing a custom profile-enrichment form, acknowledging a security notice tied to a recent account event.

i
This Builds Directly on the SPI Packaging Discipline Covered Elsewhere

Everything this guide covers about actually shipping a Custom Required Action into production — packaging, service registration, the build step, version compatibility — follows the exact same discipline covered in this series’ dedicated SPI Packaging and Deployment Strategy guide. This guide focuses specifically on what’s unique to the Required Action SPI itself, and assumes that broader packaging discipline as background.

Why Organizations Reach for This Specific Extension Point

A Custom Required Action is the right tool specifically when a mandatory, blocking step needs to be inserted into the login journey itself — as opposed to a Protocol Mapper (which shapes token contents, not login flow) or a custom Authenticator (which typically governs a specific authentication method rather than a post-authentication, one-time compliance or data-collection step).

2Architecture & Components

Let’s map every piece involved in a Custom Required Action before implementing any individual one.
graph TD
    Login["User Completes Authentication"]
    Login --> Check["Keycloak Checks Every
Registered Required Action"] Check --> Trigger["evaluateTriggers()
Decides If This Action Applies"] Trigger -->|"Applies"| Set["Action Added to
User's Required Actions"] Set --> Challenge["requiredActionChallenge()
Renders the Step's UI"] Challenge --> Submit["User Submits the Step"] Submit --> Process["processAction()
Validates and Completes"] Process --> Continue["Login Proceeds"]
Fig 2.1 — The full lifecycle a Custom Required Action moves through, from evaluation to completion
Contract

RequiredActionProvider Interface

The core interface a Custom Required Action implements, defining the methods covered fully in Chapter 4.

Registration

RequiredActionFactory

The Factory counterpart, following the Provider/Provider Factory pattern covered in this series’ SPI packaging guide, responsible for creating instances and exposing the action’s display name.

Presentation

FreeMarker Template

The template rendering the actual page the user interacts with — covered fully in Chapter 6.

Storage

User’s Required Actions Set

Where Keycloak tracks which Required Actions are currently pending for a specific user, until each is completed.

3Deep Dive: How a Required Action Gets Assigned to a User

Before a Custom Required Action can run, it needs to actually become associated with a specific user — there are two genuinely distinct ways this happens.

Explicit Assignment

An administrator, or an automated administrative process, can directly add a specific Required Action to a specific user’s account — the same mechanism covered in this series’ beginner-level guide for a built-in Required Action, applying equally to a custom one.

Dynamic Evaluation via evaluateTriggers

A Custom Required Action can also decide, dynamically and on its own, whether it applies to a given user at the moment of login, through a method called during the login flow specifically for this purpose — covered in full in Chapter 4. This lets a Required Action trigger itself based on live conditions (an outdated profile field, an unacknowledged policy update) rather than requiring an administrator to manually flag every affected user individually.

Production Example: Detecting an Outdated Terms-of-Service Acceptance

A Custom Required Action built to enforce acceptance of an updated terms-of-service document can check, every time a user logs in, whether that user’s own recorded acceptance timestamp predates the document’s most recent revision date, dynamically triggering the mandatory acceptance step only for users who genuinely haven’t yet accepted the current version — without any administrator needing to manually flag each affected account.

Combining Both Mechanisms in a Single Deployment

These two mechanisms aren’t mutually exclusive — many real deployments use both together for the same Custom Required Action, relying on dynamic evaluation as the everyday, ongoing mechanism while retaining explicit assignment as a deliberate escape hatch for an unusual, one-off case an administrator needs to force even outside the action’s own ordinary trigger condition, such as re-presenting a step to one specific user during an active investigation.

Performance Considerations for evaluateTriggers

Because evaluateTriggers runs on every single login for every user, its own implementation needs to be genuinely fast and lightweight — a slow, expensive check here (an unnecessary external network call, say) adds direct, real latency to every ordinary login across the entire Realm, not just the comparatively rare logins where the action actually ends up triggering.

4Deep Dive: The RequiredActionProvider Interface’s Core Methods

Let’s examine the actual contract a Custom Required Action implements, method by method.

evaluateTriggers

Called during the login flow for every user, this method lets a Custom Required Action inspect the current user and context, and dynamically add itself to that user’s set of pending Required Actions if its own custom condition is met — the mechanism behind the dynamic evaluation covered in Chapter 3.

requiredActionChallenge

Once an action is pending for a user, this method is called to actually render the interactive step the user sees and interacts with — typically a custom FreeMarker template, covered in Chapter 6, presenting whatever form or acknowledgment the action requires.

processAction

Called when the user submits the rendered challenge, this method validates the submission and, if successful, marks the action as complete for that user, allowing the login to proceed; if validation fails, it can re-render the challenge with an error, exactly as a built-in Required Action would.

i
These Three Methods Map Directly Onto the Diagram in Chapter 2

It’s worth explicitly connecting these method names back to Figure 2.1’s diagram: evaluateTriggers is the decision point, requiredActionChallenge is the presentation step, and processAction is the validation-and-completion step — understanding this direct mapping makes the rest of this guide’s discussion of ordering, testing, and failure modes considerably easier to follow.

5Deep Dive: Ordering and Priority Among Multiple Required Actions

A user can have several Required Actions pending simultaneously — a genuinely important, easy-to-overlook consideration when designing a custom one.

How Keycloak Determines the Order

Each Required Action, whether built-in or custom, declares its own priority, and Keycloak presents pending actions to the user in that declared order, one at a time, only moving to the next once the current one is completed.

Why Priority Deserves Deliberate, Explicit Thought

A Custom Required Action’s priority relative to Keycloak’s own built-in ones directly shapes the user’s actual experience — presenting a lengthy custom profile-enrichment form before a critical, security-sensitive built-in action like configuring two-factor authentication, for instance, could delay an important security step behind a comparatively less urgent one, an ordering choice that deserves to be made deliberately rather than left to whatever default priority value happens to apply.

Production Example: Sequencing a Security Notice Ahead of Routine Profile Updates

An organization adding a Custom Required Action to acknowledge an urgent, account-specific security notice would generally assign it a higher priority than a routine, custom profile-completion action, ensuring the security-relevant step is never delayed behind a lower-urgency one for any user who happens to have both pending simultaneously.

6Deep Dive: Building the User-Facing Template

The actual page a user sees and interacts with is a genuinely important, often underestimated part of building a Custom Required Action well.

FreeMarker Templates and Keycloak’s Theming System

Keycloak renders its login-related pages, including a Required Action’s own challenge page, using FreeMarker templates, tied into Keycloak’s broader theming system. A Custom Required Action typically ships its own dedicated template, styled consistently with the organization’s existing login theme rather than looking like an unrelated, bolted-on addition.

Designing for Clarity Under Real, Time-Pressured Conditions

Because a Required Action genuinely blocks a user’s login until it’s completed, the page needs to be immediately understandable — what’s being asked, why, and what happens next — since a user encountering this mid-login is typically trying to get into whatever application they were actually headed toward, not to read a lengthy explanation.

!
A Confusing or Broken Custom Challenge Page Can Lock Every Affected User Out

Because completing a Required Action is mandatory for login to proceed, a bug in the challenge page’s own rendering, or a genuinely confusing design that leaves users unsure how to actually complete it, doesn’t just create a poor experience — it can functionally block affected users from logging in at all, making thorough testing of this specific page, covered in Chapter 12, especially important before any production rollout.

Providing a Genuine, Working Way Out When Appropriate

Depending on the specific action’s own purpose, it’s often worth deliberately including a clear, working path for a user who genuinely cannot complete the step right now — a link to contact support, or, where appropriate, an explicit option to defer the action briefly rather than being permanently stuck. Not every Custom Required Action can or should offer this kind of escape hatch, but for those where a genuine, unresolvable edge case is plausible, designing for it deliberately is far better than a user discovering, the hard way, that no such path actually exists.

Localization and Accessibility Deserve the Same Attention as Any Other Page

Because a Custom Required Action’s challenge page is a genuine, first-class part of the login experience, it deserves the same localization and accessibility treatment given to any other themed Keycloak page — properly externalized, translatable text rather than hard-coded strings, and markup that works correctly with assistive technology, rather than being treated as a lower-priority, internal-only addition simply because it was custom-built rather than part of Keycloak’s own out-of-the-box default theme.

7Internal Working: The Full Login-Time Sequence

Let’s trace exactly what happens, step by step, from a user’s credentials being accepted through a Custom Required Action being fully resolved.
1

Primary Authentication Succeeds

The user’s credentials are validated through the ordinary Authentication Flow, covered elsewhere in this series.

2

Every Registered Required Action’s evaluateTriggers Runs

Keycloak calls this method on every registered Required Action, built-in and custom alike, letting each one dynamically decide whether it applies to this specific user right now.

3

Pending Actions Are Ordered by Priority

Every action now pending for this user — whether explicitly assigned or dynamically triggered — is ordered according to the priority values covered in Chapter 5.

4

The First Pending Action’s Challenge Is Rendered

requiredActionChallenge is called, presenting the first action’s own custom template to the user.

5

User Submits, processAction Validates, and the Cycle Repeats

Once processAction successfully completes the current action, Keycloak moves to the next pending action in priority order, repeating until every pending action is resolved and the login can finally proceed.

8Data Flow & Lifecycle

Beyond a single login’s sequence, a Custom Required Action moves through its own broader lifecycle across a user’s relationship with it over time.

Registration. The Custom Required Action is packaged and deployed following the SPI discipline covered in this series’ packaging guide, then enabled within a Realm’s own settings.

Dynamic or Explicit Assignment. The action becomes pending for a specific user, either through its own evaluateTriggers logic or explicit administrative assignment, as covered in Chapter 3.

Presentation and Completion. The user encounters and completes the action during a subsequent login, following the sequence traced in Chapter 7.

State Persisted. Whatever the action actually accomplished (recording a terms-of-service acceptance, storing a completed profile field) is persisted, so the action doesn’t trigger again for that same user unless its own evaluateTriggers logic determines it’s needed again in the future.

Retirement or Update. Eventually, the action may be retired once no longer needed, or updated with new logic (a new terms-of-service revision date, for instance) that causes it to become newly relevant for users who had already completed an earlier version of it.

graph LR
    A["Deployed & Enabled"] --> B["Triggered for
a Specific User"] B --> C["Presented and
Completed at Login"] C --> D["Completion State
Persisted"] D --> E{"Logic Updated
or New Trigger?"} E -->|"Yes"| B E -->|"No"| F["Remains Complete
for This User"]
Fig 8.1 — The full lifecycle of a Custom Required Action across a user’s ongoing relationship with it

9Deep Dive: Storing State Associated With a Custom Required Action

A Custom Required Action frequently needs to remember something about a specific user — worth understanding the sound patterns for doing this.

User Attributes as the Common Storage Mechanism

A Custom Required Action commonly stores its own state — a terms-of-service acceptance timestamp, a completed enrollment flag — as a custom User Attribute, the same general-purpose, extensible storage mechanism Keycloak offers for attaching arbitrary additional data to a user’s profile.

Designing evaluateTriggers Against This Stored State

The evaluateTriggers method covered in Chapter 4 typically reads back this same stored attribute to decide whether the action still applies — comparing a stored acceptance timestamp against a current policy-revision date, for instance — closing the loop between what processAction wrote and what evaluateTriggers checks on every subsequent login.

Production Example: A Versioned Acceptance Attribute

Rather than storing a simple true-or-false “accepted” flag, a well-designed terms-of-service Custom Required Action stores the specific version number or revision date that was actually accepted, letting evaluateTriggers compare that stored value directly against the current document’s own version — automatically and correctly re-triggering the action the next time the document is revised, without any extra logic needed to explicitly reset a simple flag when that happens.

10Deep Dive: Interaction With Identity Brokering and Federated Users

A genuinely advanced consideration: how a Custom Required Action behaves for a user who authenticated through an external Identity Provider rather than logging in directly.

Required Actions Still Apply to Brokered Logins

As covered in this series’ Identity Brokering guide, a user authenticating through an external Identity Provider still passes through Keycloak’s own post-authentication processing, including any pending Required Actions — a Custom Required Action generally applies to a brokered user exactly as it would to a directly authenticated one, unless deliberately designed otherwise.

Why This Deserves Explicit Design Attention

Some Custom Required Actions genuinely make sense for a brokered user (an internal terms-of-service acceptance, say), while others might not (a step tied specifically to a locally managed credential that a brokered user, authenticating entirely through an external identity, may not actually have). A well-designed evaluateTriggers implementation explicitly checks whether the current user is a brokered or federated identity, where relevant, rather than assuming every user reaching this point arrived the same way.

i
First Broker Login Is a Related but Distinct Extension Point

This series’ Identity Brokering guide covers the First Broker Login flow as its own, separate extension point specifically for a user’s very first brokered login. A Custom Required Action and a First Broker Login customization can complement each other, but they serve genuinely different moments — the latter runs specifically on first brokered login, while a Required Action can apply on any login, brokered or not, whenever its own trigger condition is met.

Handling User Attributes That May Not Exist for Every Identity Source

A Custom Required Action reading a specific User Attribute, as covered in Chapter 9, needs to handle the genuine possibility that a brokered or federated user might not have that attribute populated the same way a directly registered, locally managed user would — a defensive evaluateTriggers implementation checks for a missing or unexpected value explicitly, rather than assuming every user reaching this point shares an identical underlying profile shape.

Coordinating With User Federation for Externally Managed Attributes

Where a Realm also integrates User Federation, covered elsewhere in this series’ broader identity-management content, some user attributes may originate from and be managed by an external system rather than Keycloak’s own local storage. A Custom Required Action attempting to write back a completion flag or timestamp needs to account for whether that specific attribute is genuinely writable from Keycloak’s side at all, rather than assuming every attribute behaves identically regardless of where the underlying data actually lives, and should fall back to a Keycloak-local attribute instead when the natural choice turns out not to be writable.

11Advantages, Disadvantages & Trade-offs

Building a Custom Required Action is genuinely powerful, but it’s a real engineering investment carrying its own honest costs.

Advantages

  • Lets an organization enforce a genuinely custom, mandatory step no built-in option covers, directly inside the login journey itself
  • Dynamic evaluation via evaluateTriggers avoids needing to manually flag every affected user individually
  • Integrates natively with Keycloak’s own theming and login-flow infrastructure, rather than requiring a separate, bolted-on system
  • Applies consistently across every application relying on this Realm, centralizing enforcement in one place

Disadvantages & Trade-offs

  • A poorly designed or buggy custom challenge page can functionally lock affected users out of login entirely, as covered in Chapter 6
  • Requires the same full SPI packaging, testing, and version-compatibility discipline covered in this series’ dedicated packaging guide
  • Priority ordering relative to other Required Actions needs deliberate, explicit design attention rather than being left to a default
  • Storing and evolving associated user state (as covered in Chapter 9) needs careful thought to remain correct as underlying business logic changes over time

12Deep Dive: Testing a Custom Required Action Thoroughly

Given the real risk of a broken custom action blocking login entirely, testing strategy deserves dedicated, advanced treatment.

Testing evaluateTriggers Logic in Isolation

The dynamic triggering condition itself can generally be unit tested in isolation, covering the range of user states that should and shouldn’t trigger the action — confirming, for instance, that a user who already accepted the current terms-of-service revision is correctly never presented with the challenge again.

Testing the Full Login Sequence End to End

Beyond isolated logic, a genuinely thorough test exercises the full sequence traced in Chapter 7 against a real, running Keycloak instance — confirming the challenge page actually renders correctly, that a valid submission genuinely completes the action and allows login to proceed, and that an invalid submission is correctly rejected with a clear, actionable error rather than a confusing dead end.

Production Example: A Staged Rollout to a Limited User Segment

Beyond automated testing, a cautious organization rolling out a new Custom Required Action for the first time might enable it initially for only a small, limited segment of real users — internal staff, for instance — confirming it behaves correctly under genuine, real-world conditions before extending its evaluateTriggers logic to apply more broadly across the entire user base.

13Security

A Custom Required Action sits directly inside the login path, making its own security properties genuinely consequential.
ADR-013: Trusting Unvalidated Input Inside processAction Anti-pattern Warning
Problem

A Custom Required Action’s processAction implementation accepts whatever the user submits and stores it directly, without validating it against the same rigor any other user-facing form submission in the broader application would receive.

Why It Fails

Because processAction runs with the same trust and access as any other part of Keycloak’s own core login processing, insufficient input validation here carries the same class of risk as anywhere else user input meets persistent storage or downstream processing — and because this code sits directly inside the mandatory login path, a resulting bug or vulnerability here potentially affects every single user who encounters the action.

Correct Approach

Apply the same input-validation rigor to a Custom Required Action’s processAction implementation as to any other genuinely security-relevant, user-facing form, treating its position inside the core login path as a reason for more scrutiny, not less.

Ensuring a Required Action Cannot Be Bypassed

A Custom Required Action’s whole value depends on it genuinely being mandatory — a well-tested implementation confirms there’s no path through the login flow that allows a pending action to be silently skipped, whether through a direct API call, an unusual authentication method, or an edge case in how the action interacts with other flows, such as the brokered-login scenario covered in Chapter 10.

Avoiding Sensitive Data Exposure in the Challenge Page Itself

If a Custom Required Action’s challenge page displays any of the user’s own existing data back to them — a partially completed profile, say — that data should be handled with the same care given to any other page displaying personal information, including confirming it’s only ever shown to the actual account owner and never inadvertently logged in plaintext anywhere along the way.

Guarding Against a Malicious Actor Exploiting the Action Itself

Because a Custom Required Action runs with the same privileged position inside the login path as any built-in one, it’s worth explicitly considering whether its own logic could be abused — could a crafted submission to processAction be used to modify data belonging to a different user than the one currently authenticating, for instance, if the implementation doesn’t carefully scope its own writes to the specific, currently authenticating user’s own identifier. This class of vulnerability is subtle precisely because it lives inside code many teams assume is inherently safe simply because it’s part of the login flow, rather than treating it with the same scrutiny given to any other genuinely security-sensitive code path.

Rate-Limiting Repeated Failed Submissions

If a Custom Required Action’s processAction validates a value against some external check — verifying a submitted code, for instance — it deserves the same rate-limiting consideration given to any other credential-adjacent verification step, following the same principle covered in this series’ Brute Force Protection tuning guide, to avoid this specific step becoming its own, separate avenue for automated, repeated guessing that bypasses the protection already applied to the ordinary login form itself.

14Monitoring, Logging & Metrics

Because a Custom Required Action can directly block login, its real-world behavior deserves dedicated, ongoing observability.
Completion Rate

Trigger-to-Completion Funnel

Tracking how many users who encounter the challenge actually complete it successfully, versus abandoning the login entirely at that point.

Errors

processAction Validation Failures

Monitoring how often submissions are rejected, and why, can reveal a confusing or poorly designed challenge page well before it generates a flood of support requests.

Coverage

evaluateTriggers Activation Volume

Tracking how many users the dynamic trigger condition actually affects helps confirm it’s behaving as intended, neither over-triggering for users who shouldn’t see it nor under-triggering for those who should.

Audit

Completion Events in the Broader Audit Trail

Recording a Custom Required Action’s completion as its own event, correlated using the audit-trail approach covered elsewhere in this series, supports later review of exactly when and for whom the action was satisfied.

Watching for an Unusually High Abandonment Rate

A sharp, sudden increase in the rate at which users abandon login specifically at this challenge step is a strong, early signal of a genuine problem — a confusing redesign, a subtle bug in requiredActionChallenge’s rendering — and deserves the same urgency as any other metric indicating users are being unexpectedly blocked from a core, essential flow.

Segmenting Metrics by User Population Where Relevant

Given Chapter 10’s discussion of brokered and federated users potentially experiencing a Custom Required Action differently, it’s worth breaking completion and abandonment metrics down by this same segmentation rather than only reviewing one blended, aggregate figure — a problem affecting specifically brokered users, for instance, could otherwise be diluted into an aggregate number that still looks broadly acceptable overall.

15Design Patterns & Anti-patterns

A handful of consistent habits distinguish a genuinely well-built Custom Required Action from a fragile, poorly considered one.

Good Patterns

  • Store versioned state (a revision date, not a simple flag) so evaluateTriggers naturally handles future policy or requirement changes without extra logic
  • Assign priority deliberately, weighing a custom action’s own urgency against Keycloak’s built-in Required Actions rather than accepting a default
  • Test the full end-to-end login sequence against a real, running Keycloak instance, not just the triggering logic in isolation
  • Roll out cautiously to a limited segment first before broadening a new action’s trigger condition to the entire user base

Anti-patterns to Avoid

Common Mistakes

  • Insufficiently validating user input inside processAction, as covered in Chapter 13
  • Designing a confusing or poorly tested challenge page that can functionally lock affected users out of login
  • Storing a simple boolean completion flag instead of versioned state, requiring extra, error-prone logic to correctly handle future changes
  • Failing to consider how the action behaves for brokered or federated users, as covered in Chapter 10

16Best Practices & Common Mistakes

A concentrated, practical checklist drawing together the guidance from throughout this guide.
PracticeWhy It Matters
Keep the challenge page’s request immediately clear and simpleA user encountering it is mid-login and typically wants to reach their actual destination quickly
Validate every submission inside processAction rigorouslyThis code sits directly inside Keycloak’s core, mandatory login path
Explicitly assign a deliberate priority relative to other Required ActionsAvoids accidentally delaying a more urgent action behind a less urgent one
Monitor completion and abandonment rates continuouslyA blocking step’s failure mode directly prevents users from logging in at all
Test explicitly against brokered and federated user scenariosAssumptions that hold for directly authenticated users don’t automatically hold for brokered ones

The Single Most Common Mistake: Underestimating the Challenge Page’s Importance

Teams frequently invest careful engineering effort into a Custom Required Action’s underlying triggering and validation logic while treating the actual user-facing challenge page as an afterthought — exactly backwards, given that this page is the one part of the entire implementation every single affected user will directly, personally encounter.

17Real-World & Industry Examples

Custom Required Actions underpin a genuine range of real, production compliance and onboarding needs across different organizations.

Financial Services Enforcing Regulatory Disclosures

A bank frequently needs users to acknowledge a specific regulatory disclosure whenever its content is updated, implementing this as a Custom Required Action with versioned acceptance state, ensuring every affected user genuinely acknowledges the current disclosure before continuing, in a way that’s centrally enforced and auditable.

Healthcare Platforms Requiring Profile Completeness

A healthcare platform might require a clinician’s profile to include a currently valid license number before allowing continued access, implementing a Custom Required Action that dynamically triggers whenever that specific field is missing or has expired, blocking further access until it’s genuinely updated.

Enterprise Platforms Enforcing Security Awareness Training

A large enterprise might require employees to acknowledge completion of an annual security-awareness training before their next login proceeds, implemented as a Custom Required Action that checks a completion timestamp against a rolling annual deadline, dynamically re-triggering for any employee whose most recent completion has aged out.

Consumer Platforms Collecting Progressive Profile Data

A consumer platform practicing progressive profiling — gradually collecting additional profile information across several logins rather than all at once during initial signup — might implement each incremental data-collection step as its own Custom Required Action, each with its own narrow, specific trigger condition based on which fields are still missing.

18Deployment & Cloud Considerations

A few further considerations specific to deploying a Custom Required Action within a modern, clustered, cloud-based Keycloak environment.

Consistency Across Cluster Nodes

Exactly as covered in this series’ SPI packaging guide, a Custom Required Action must be consistently deployed and active across every Node in a cluster, as covered in this series’ clustering guide — a user whose login happens to land on a Node missing the action (or running an older version of it) could experience genuinely inconsistent behavior depending purely on which Node handled that particular request.

Theming Consistency Across Environments

The challenge page’s own visual theme needs to remain consistent as it moves through a deployment pipeline’s successive environments, exactly like any other themed Keycloak page — a mismatch here (a staging environment showing an outdated visual theme, say) is a common, easily overlooked deployment consistency issue worth explicitly checking for during promotion.

Production Example: Bundling the Required Action and Its Theme Together

A mature deployment pipeline packages a Custom Required Action’s provider code and its associated FreeMarker template and theme assets together as one cohesive, versioned unit, ensuring the logic and its corresponding presentation always travel through the deployment pipeline in lockstep, rather than risking a mismatch between an updated action’s logic and an unintentionally stale, unrelated version of its own presentation layer.

Feature-Flagging a New Custom Required Action

Beyond the staged rollout to a limited user segment covered in Chapter 12, some organizations wrap a new Custom Required Action’s own trigger condition behind an externally controlled feature flag, letting the action be enabled, disabled, or adjusted in production without requiring a full redeployment cycle for every small rollout adjustment — a pattern particularly useful during an initial, cautious rollout period where the team may need to quickly pause the action entirely if an unexpected issue surfaces.

Coordinating a Rollback With Any Already-Collected State

If a Custom Required Action needs to be rolled back after already being active in production for some period, it’s worth explicitly considering what happens to any state it already collected from users who completed it during that window — generally, this state should be left intact and simply ignored by the reverted logic, rather than actively deleted, preserving whatever value that data still holds for a future re-attempt rather than discarding real, previously collected user input purely because the enforcing logic itself is being temporarily rolled back.

Documenting the Action’s Purpose for Future Maintainers

Because a Custom Required Action’s own trigger condition can be genuinely nonobvious months or years after it was first built, it’s worth documenting explicitly, alongside the code itself, exactly why the action exists, what business or compliance requirement it satisfies, and under what condition it would be safe to eventually retire — sparing a future maintainer the task of reverse-engineering that context purely from reading the implementation on its own, long after the original author has moved on to other work.

19Frequently Asked Questions

Q1What’s the difference between a Required Action and a custom Authenticator?
A Required Action is typically a post-authentication, one-time compliance or data-collection step blocking login until completed. A custom Authenticator generally governs a specific authentication method itself, earlier in the flow. They serve genuinely different purposes even though both can block login progress.
Q2What does evaluateTriggers actually do?
It’s called on every registered Required Action during login, letting each one dynamically decide, based on the current user and context, whether it should become pending for that specific user right now — the mechanism behind dynamic, condition-based triggering.
Q3Why should I store versioned state instead of a simple completion flag?
A simple flag requires extra, error-prone logic to correctly reset whenever an underlying requirement changes. Storing the specific version or date actually satisfied lets evaluateTriggers naturally and correctly re-trigger the action whenever a newer requirement supersedes what was previously accepted.
Q4Does a Custom Required Action apply to users who log in through an external Identity Provider?
Generally yes, unless deliberately designed otherwise — a brokered login still passes through Keycloak’s post-authentication processing, including pending Required Actions, as covered in Chapter 10.
Q5How do I control the order in which multiple Required Actions are presented?
Through each action’s own declared priority value, which Keycloak uses to order pending actions for a user — a setting that deserves deliberate, explicit thought rather than being left to a default, as covered in Chapter 5.
Q6What’s the biggest risk of a poorly built Custom Required Action?
Because it’s mandatory for login to proceed, a bug in the challenge page or its validation logic can functionally lock every affected user out of login entirely, making thorough testing and a cautious, staged rollout especially important.
Q7Where should a Custom Required Action store data it collects from the user?
Commonly as a custom User Attribute, the general-purpose extensible storage mechanism Keycloak offers for attaching additional data to a user’s profile, as covered in Chapter 9.
Q8Does building a Custom Required Action require the same deployment discipline as any other SPI?
Yes — it follows the exact same packaging, registration, build-step, and version-compatibility discipline covered in this series’ dedicated SPI Packaging and Deployment Strategy guide, which this guide assumes as background.
Q9Can I disable a Custom Required Action quickly if a problem is discovered after rollout?
Yes, if it’s designed with this in mind — wrapping its trigger condition behind an externally controlled feature flag lets it be paused or adjusted in production without a full redeployment cycle, a pattern worth adopting deliberately during an initial, cautious rollout period.
Q10What should happen to data already collected by an action that later gets rolled back?
Generally, that data should be left intact rather than deleted, preserving its value for a possible future re-attempt, even while the enforcing logic itself is temporarily reverted or paused.

20Summary and Key Takeaways

“An extra checkpoint step only works if the traveler can immediately tell what it’s asking, and why.”

Key Takeaways

  • A Custom Required Action implements Keycloak’s Required Action SPI to enforce a genuinely custom, mandatory login-time step no built-in option covers.
  • Its three core methods — evaluateTriggers, requiredActionChallenge, and processAction — govern, respectively, dynamic decision-making, presentation, and validation-and-completion.
  • A user’s pending actions are ordered by priority, a setting that deserves deliberate, explicit design attention relative to Keycloak’s own built-in actions.
  • Storing versioned state rather than a simple completion flag lets a custom action naturally and correctly re-trigger whenever an underlying requirement changes.
  • Because completion is mandatory for login, a Custom Required Action’s challenge page and validation logic deserve especially rigorous testing — a defect here can functionally lock users out.
  • The action generally applies to brokered and federated logins just as it would to direct ones, unless its own trigger logic explicitly accounts for that distinction.
  • Building and shipping one safely follows the same SPI packaging and deployment discipline covered elsewhere in this series — this is an extension of that discipline, not a separate one.
  • Consider wrapping a new action’s trigger condition in a feature flag, and design any rollback to preserve already-collected user state rather than discarding it.
  • evaluateTriggers runs on every single login, so its own implementation needs to stay fast and lightweight regardless of how rarely the action actually ends up triggering.

A Custom Required Action, done well, becomes an almost invisible part of the login experience for the overwhelming majority of users who never actually encounter it, and a clear, quick, well-tested step for the specific few who do. That balance — rigorous where it needs to be, unobtrusive everywhere else — is really the whole discipline this guide has walked through, from the interface’s own three core methods through to how the action is packaged, tested, monitored, and eventually rolled back if it ever needs to be.