Access Control Best Practices

Strategies for controlling who can use your plugins — from launch rules to runtime eligibility checks.

View as Markdown

Your plugin calls APIs, reads data, and takes actions on behalf of users. Not every user should have access to every plugin. Access control is how you ensure the right people reach the right capabilities — and get a clear explanation when they don’t.

There are three strategies, and they aren’t mutually exclusive. Most production plugins combine at least two.

StrategyWhen to useLatency impact
Secure the underlying actionAlways — this is the baselineNone (handled by connector)
DSL launch rulesYou want to gate access before the conversation startsNone (evaluated at trigger time)
Runtime eligibility checksYou need a live data lookup to determine accessAdds one API call

Secure the Underlying Action

This is not optional. Regardless of what you do at the plugin layer, the downstream system should enforce its own permissions. Moveworks supports this through connector-level authentication that ties actions to the requesting user’s identity.

OAuth 2.0 Authorization Code — The user grants consent to a third-party system. Moveworks runs a preflight check before the plugin executes. If the user hasn’t authorized the connector, the assistant prompts them to grant access. The plugin only runs after all required connectors are authorized.

JWT User Claims — The user’s identity is passed in JWT claims to the target system. Every API call executes as that user, preserving the target system’s audit trail and permission model.

RPA — When API integrations aren’t available, browser-based RPA logs into applications on behalf of the user, inheriting their session-level permissions.

Connector-level auth is the only strategy that truly secures the action. Launch rules and eligibility checks control who can start a conversation — they don’t prevent a determined user from reaching the underlying API if the connector uses a shared service account. Always pair plugin-layer access control with per-user authentication on the connector.

DSL Launch Rules

Launch rules determine who can trigger a plugin. They are evaluated before the conversation starts, so there is zero latency impact on the user experience. If a user doesn’t match the rules, the reasoning engine won’t even consider the plugin when interpreting their request.

There are two modes:

  • List Mode — Allow or deny specific email addresses. Good for testing or small, fixed audiences.
  • Advanced Mode — Write DSL expressions that evaluate against user attributes. This is where attribute-based access control happens.

See Launch Permissions for the full configuration reference.

Sync Attributes for Fast Evaluation

DSL launch rules evaluate against the user record in Moveworks. If the attributes you need aren’t there yet, sync them from your identity provider through the Identity Gateway.

For example, if your organization tracks admin access eligibility in an Active Directory group:

1

Map the attribute in the Identity Gateway

Sync the group membership as a custom attribute on the user record. For example, map an AD group like Local-Admin-Access to a custom attribute has_local_admin_access.

2

Write a DSL launch rule

In the plugin’s launch configuration, switch to Advanced Mode and write a DSL expression:

user.custom_attributes.has_local_admin_access == true

You can combine multiple conditions:

user.department == "Engineering" AND user.custom_attributes.has_local_admin_access == true

This approach works well when:

  • Latency matters — No API call happens at conversation time. The evaluation is instant.
  • Attributes don’t change frequently — Group memberships, department, role, and license assignments are typically stable enough that syncing on a schedule is acceptable.
  • You want to hide the plugin entirely — Users who don’t match the rules never see the plugin surface in the assistant. There’s no “you don’t have access” message because they never encounter it.

Check the User Attribute Reference for the full list of attributes available in DSL expressions.

Common DSL Patterns

Use caseDSL expression
Department restrictionuser.department == "HR"
Role-based accessuser.role == "manager"
Location + departmentuser.department == "Engineering" AND user.location == "New York"
Custom attribute (boolean)user.custom_attributes.has_vpn_access == true
Multiple groups (OR)user.department == "IT" OR user.department == "Security"
Exclude contractorsuser.employment_type != "contractor"

Runtime Eligibility Checks

Sometimes you can’t determine access from static attributes alone. The eligibility decision requires live data — a ServiceNow group membership, an approval status in a ticketing system, or a calculation that spans multiple systems. In these cases, you run the access check inside the conversation process at runtime.

The pattern is:

  1. Action Activity — Call an API to check the user’s eligibility. Store the result in the data bank.
  2. Decision Policy — Evaluate the result with DSL. Branch based on whether the user passes.
  3. Content Activity (denial path) — If the user fails the check, display a clear explanation of why they don’t have access and what they can do next.
  4. Continue (success path) — If the user passes, proceed with the plugin’s main flow.

Worked Example: Local Admin Access

A user asks to elevate their local admin privileges. Before running the provisioning action, the plugin needs to verify the user is eligible by checking their department, role, and whether they’ve completed the required security training — data that spans ServiceNow and a compliance system.

1

Build the eligibility check action

Create an HTTP action (or compound action) that queries the relevant systems and returns an eligibility result. The output should include a clear boolean and a reason for denial.

Example response
1{
2 "eligible": false,
3 "reason": "Security training certification expired on 2025-11-15.",
4 "next_step": "Complete the Security Awareness Training at https://training.example.com"
5}
2

Add the action as the first activity

In the conversation process, add the eligibility check as the first action activity. Map the user’s identity into the request and store the result:

FieldValue
Actioncheck_admin_eligibility
Input Mappingemployee_id: data.user_info.rec_id
Output Mappingeligibility: response
3

Add a decision policy

Branch on the eligibility result:

Decision Policy DSL
1# Case 1: Eligible
2data.eligibility.eligible == true
3
4# Case 2: Not eligible
5data.eligibility.eligible == false
4

Configure the denial path

On the Not eligible branch, add a content activity that explains the denial. Use the reason and next step from the API response so the user gets a specific, actionable explanation — not a generic “access denied.”

The reasoning engine reads the content activity’s data and can incorporate data.eligibility.reason and data.eligibility.next_step into its response, giving the user a natural-language explanation of what happened and what to do next.

5

Configure the success path

On the Eligible branch, continue with the plugin’s main flow (e.g., the provisioning action).

The eligibility check action runs as an activity inside the conversation process, so the user has already triggered the plugin. Unlike DSL launch rules, they will see the plugin — they just receive a clear explanation if they don’t qualify. Design your denial message to be helpful, not just a dead end.

When to Use Runtime Checks

Runtime eligibility checks add latency (one or more API calls before the main flow starts), so only use them when the data can’t be synced ahead of time:

  • Data changes frequently — Real-time group memberships, approval statuses, or certification expirations.
  • Data spans multiple systems — Eligibility requires joining data from ServiceNow, an HR system, and a compliance tool.
  • Complex evaluation logic — Department hierarchy lookups, org-chart traversals, or custom business rules that don’t fit into a DSL expression.

Choosing the Right Strategy

Use this decision flow to pick your approach:

Most production plugins combine strategies:

  • OAuth connector + DSL launch rule — The connector secures the action; the launch rule prevents unlicensed users from even starting the conversation.
  • DSL launch rule + runtime check — The launch rule filters out obviously ineligible users fast; the runtime check handles edge cases that require live data.
  • All three — OAuth secures the action, a launch rule gates on department/role, and a runtime check verifies training certification before executing.

Start with the simplest strategy that meets your requirements. Add complexity only when the simpler approach doesn’t cover your use case. DSL launch rules handle the majority of access control needs without any runtime cost.