Pluggable Security
Without pluggable security, a workflow engine must either manage its own users and roles - adding a second identity system to maintain - or hard-code authorization logic that cannot adapt to different deployments. Every transition, every command, needs a permission check, but the identity source changes from one organization to the next.
Pluggable security is a provider interface - IWorkflowRuleProvider - that delegates every authorization decision to your application code. Workflow Engine never stores passwords, manages users, or maintains role hierarchies. It asks your code: "Can this person execute this command on this process instance?"
With pluggable security, you connect Workflow Engine to your existing identity system in one integration point. For example, a rule named "Manager" on an approval transition causes your provider to check whether the calling user belongs to the Manager group in Active Directory, Azure AD, or your own user table - whatever you implement.
What it is
Think of the rule provider as a security guard that your company trains. You teach the guard how to recognize authorized people - by checking your employee directory, your SSO system, your custom database - and the guard stands at every door (transition) and makes the call. Workflow Engine does not need to know how your directory works. It just asks the guard: "Is this person allowed through this door?"
When a user executes a command on a process instance, the runtime evaluates every outgoing transition from the current activity. For each transition, it asks the rule provider: can this user pass? If the provider says no, the runtime tries the next transition. If no transition passes, the command fails.
The provider receives the user's identity ID, the rule name, and an optional parameter - typically a role name, a group name, or a permission string. The provider's job is to return true or false.
For developers: Implement IWorkflowRuleProvider, which has seven members: synchronous (GetRules, Check, GetIdentities) and asynchronous variants (CheckAsync, GetIdentitiesAsync), plus IsCheckAsync and IsGetIdentitiesAsync to declare which variant the runtime should use. Register the implementation with runtime.WithRuleProvider(new MyRuleProvider()). The Check / CheckAsync methods receive the process instance, the runtime reference, the user's identity ID, the rule name, and an optional parameter string. See the Rules concept page for the full interface and implementation walkthrough.
Why it matters
Pluggable security delivers these outcomes:
- Your identity system stays in charge - No user synchronization, no password storage, no role duplication. Workflow Engine never becomes a second source of truth for who can do what. If you deactivate a user in Active Directory, that user immediately loses access to all workflows.
- One integration point for all authorization - Implement one interface and every transition in every scheme uses it. There is no per-transaction or per-activity authorization code to scatter across your integration. The rule provider is the single funnel for all command authorization.
- Works with any identity provider - Active Directory, Azure AD, Okta, Auth0, LDAP, a custom SQL database, a REST API - if your application code can query it, your rule provider can use it. See the Active Directory plugin for a reference implementation.
- No lock-in to the provider choice - Swap from LDAP to Azure AD by replacing the rule provider implementation. No scheme changes, no model changes, no database changes. The runtime only depends on the interface, not the implementation.
Who it is for
Evaluator (CEO, CTO, PM): Pluggable security means Workflow Engine adapts to your existing security infrastructure rather than forcing you to adapt to it. You do not need to provision users, sync directories, or manage roles inside the workflow engine. Your security team's existing processes - onboarding, offboarding, role changes - continue to work unchanged.
Developer: You implement a single interface (IWorkflowRuleProvider) with a Check method that queries your identity system. Register it with runtime.WithRuleProvider(). The runtime calls your provider on every command execution. See the Rules concept page for code examples and the DeactivatedWorkflowRuleProvider wrapper for toggling providers on and off at runtime.
Enterprise architect: The rule provider interface is the authorization perimeter for all workflow operations. Combined with the HTTP API or Web API, you can deploy Workflow Engine with no direct access to your identity infrastructure - only the provider implementation knows how to reach Active Directory or Azure AD. Audit all authorization decisions by wrapping a logging provider around your real implementation.
When to use it
Use pluggable security in any deployment that needs command-level authorization - which is almost every deployment. Typical scenarios:
- Role-based transitions on a purchase approval process - Only users in the "Manager" role can approve requisitions above $5,000. The rule provider checks the user's role memberships against the rule name on each transition.
- Group-based document review - Only members of the "Legal Review" group can advance a contract to the signature stage. The scheme designer creates a rule named "LegalReviewGroup" and the provider resolves it against the identity system.
- User-level self-service - Only the original requestor can cancel their own expense report. The provider checks the identity ID from the user context against a process parameter that stores the requestor ID.
- Integration with an existing custom auth system - Your application has a custom permissions table with fine-grained resource-level access. The rule provider queries that table using the rule name (which encodes a permission key) and the optional parameter (which encodes the resource scope).
How it compares
The table below compares Workflow Engine's pluggable security approach with the alternative of built-in user management in the engine.
| Approach | What it requires | Result |
|---|---|---|
| Built-in user management in the engine | The engine stores users, roles, and passwords. User lifecycle (onboarding, offboarding, role changes) must be managed in two places. Password policies, MFA, and SSO integration become the engine's problem. | Two identity systems to maintain. Engine must be kept secure as a user store. Difficult to meet enterprise security compliance. |
| Workflow Engine pluggable security | Implement IWorkflowRuleProvider. Register it with runtime.WithRuleProvider(). The engine delegates every authorization check to your code. | One identity system - yours. No user data in the engine. Compliance stays in your existing infrastructure. |
Frequently asked questions
What identity systems does Workflow Engine support?
Any system your application code can query - Active Directory, Azure AD, Okta, Auth0, LDAP, a custom SQL database, a REST API - through the IWorkflowRuleProvider interface. There is no built-in user store, no login page, no password validation. Workflow Engine does not impose a specific identity provider. See the Active Directory plugin for an out-of-box implementation.
How does Workflow Engine know who the current user is?
The calling code passes the user's identity ID to every runtime API method (ExecuteCommand, GetAvailableCommands, etc.). In an ASP.NET Core application, you typically extract this from HttpContext.User.Identity.Name or a JWT claim and pass it to the API calls. Workflow Engine does not read HttpContext - the identity ID is an explicit parameter on every command-related method.
When are rules evaluated during process execution?
Rules are evaluated on every command execution (ExecuteCommand, ExecuteCommandWithParameters, etc.). The runtime evaluates all restrictions on every outgoing transition from the current activity. If a transition has no restrictions, it is available to all users. If the rule provider returns false for a restriction, the user is blocked from that transition. If all outgoing transitions are blocked, the command fails with no matching transition. If a referenced rule name is not implemented by any provider or code action, the runtime throws NotImplementedException.
Can I have multiple rule providers registered at the same time?
Yes. Each call to WithRuleProvider adds the provider to an aggregation chain. The runtime queries providers in registration order and returns true if any provider returns true for the rule. This lets you compose providers: a role-based provider handles most transitions, while a special-case provider handles override scenarios for administrators.