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
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.
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
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"]
RequiredActionProvider Interface
The core interface a Custom Required Action implements, defining the methods covered fully in Chapter 4.
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.
FreeMarker Template
The template rendering the actual page the user interacts with — covered fully in Chapter 6.
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
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
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.
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
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
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.
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
Primary Authentication Succeeds
The user’s credentials are validated through the ordinary Authentication Flow, covered elsewhere in this series.
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.
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.
The First Pending Action’s Challenge Is Rendered
requiredActionChallenge is called, presenting the first action’s own custom template to the user.
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
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"]
9Deep Dive: Storing State Associated With a Custom Required Action
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
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.
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
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
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
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
Trigger-to-Completion Funnel
Tracking how many users who encounter the challenge actually complete it successfully, versus abandoning the login entirely at that point.
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.
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.
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
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
| Practice | Why It Matters |
|---|---|
| Keep the challenge page’s request immediately clear and simple | A user encountering it is mid-login and typically wants to reach their actual destination quickly |
| Validate every submission inside processAction rigorously | This code sits directly inside Keycloak’s core, mandatory login path |
| Explicitly assign a deliberate priority relative to other Required Actions | Avoids accidentally delaying a more urgent action behind a less urgent one |
| Monitor completion and abandonment rates continuously | A blocking step’s failure mode directly prevents users from logging in at all |
| Test explicitly against brokered and federated user scenarios | Assumptions 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
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
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
20Summary and Key Takeaways
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.