Impersonation in Dataverse plug-ins

How impersonation works in Dataverse plug-ins — running as the calling user vs system user, the SDK patterns, and the security implications.

Updated 2026-09-26

By default, a Dataverse plug-in runs with the privileges of the user who triggered the operation. Sometimes the plug-in needs different privileges — to access data the calling user can't see, to update records they couldn't update, or to assume a specific role. Impersonation is the mechanism. Used carefully, it's powerful; used carelessly, it's a security hole.

The default behaviour. Without impersonation:

  • Plug-in runs as the calling user.
  • Plug-in's data access respects user's security roles.
  • Plug-in can do anything the user could do — no more, no less.

This is the safe default; honour user permissions.

The system user. Inside a plug-in:

  • context.UserId — the calling user.
  • context.InitiatingUserId — same in most cases.
  • IOrganizationServiceFactory.CreateOrganizationService(null) — creates a service running as system user (super-privileged).

The system user can do anything; respects no security roles.

Common reasons to use system user.

  • Cross-team operations — plug-in needs to read records from other teams.
  • Cascade updates — plug-in updates related records the user doesn't own.
  • Audit logging — log to an audit table the user can't write.
  • Integration scenarios — service-to-service operations.

The risk. When plug-in runs as system:

  • User's privilege boundaries bypassed.
  • User can indirectly do things they couldn't directly.
  • Data exposure if return values include unauthorised data.

The mitigation: validate user authorisation explicitly within the plug-in, then perform privileged operations.

Specific user impersonation. Instead of system user, impersonate a specific user:

var service = serviceFactory.CreateOrganizationService(specificUserId);

Operations run as that user, respecting their security roles.

Use case for specific impersonation. A workflow that creates records on behalf of a specific group account:

  • Multiple users invoke the workflow.
  • All resulting records should be owned by a service account.
  • Impersonate the service account.

This gives consistent ownership without elevating to system.

Pattern: validate then elevate.

// 1. Validate user authorisation explicitly.
if (!UserCanPerformOperation(callingUser, recordId))
{
    throw new InvalidPluginExecutionException("Not authorised");
}

// 2. Elevate to system for actual operation.
var systemService = serviceFactory.CreateOrganizationService(null);
systemService.Update(record);

This pattern keeps user authorisation strict while accomplishing the work that requires elevation.

Recursion considerations. When impersonating, plug-ins on the resulting operations may run differently:

  • A plug-in fires on the record update.
  • That plug-in sees the impersonated context, not the original user.
  • Cascade behaviour can be unexpected.

Document and test carefully.

Audit trail. Operations performed via impersonation:

  • The audit trail shows the impersonating identity.
  • May or may not preserve the original user information.
  • For accountability, log the original user separately within plug-in trace.

Workflow steps and impersonation. Workflow steps have their own context:

  • Run as owner — the workflow record's owner.
  • Run as user who triggered.

Choose based on whether elevated access is needed.

Power Automate impersonation. Flows have similar concepts:

  • Connection identity — typically the user who created the connection.
  • Run-only users — for shared flows.
  • Service principal connections — bypass user identity.

Each pattern has security implications.

Cross-tenant impersonation. Not natively supported; cross-tenant requires specific setup (B2B users, multi-tenant apps).

Common pitfalls.

  • Default to system user. Unnecessarily elevates; security risk.
  • No authorisation check. Impersonation bypasses user permissions; user effectively elevated.
  • Audit trail unclear. Can't tell who actually did what.
  • Performance impact. Creating separate service instances has overhead.
  • Cascade effects. Downstream plug-ins see different context than expected.

Best practices.

  • Use default user context where possible. Impersonate only when needed.
  • Validate explicitly when impersonating. Don't assume permission.
  • Log the original user. Even if technical operation is as system, log who initiated.
  • Document the impersonation rationale. Why this plug-in needs elevated access.
  • Code review for impersonation. Treat impersonation as security-sensitive code.

Comparison with simpler patterns.

  • Sharing record — give specific user/team access; user keeps their identity.
  • Field-level security — control which columns user sees.
  • Hierarchical security — manager sees direct reports.

Sometimes these solve the problem without needing impersonation.

Compliance considerations.

  • SOX — segregation of duties; impersonation may breach.
  • GDPR — accountability for who accessed personal data.
  • Internal audit — review plug-ins using impersonation.

Strategic positioning. Impersonation is a power-tool. Use sparingly, with clear rationale, with explicit authorisation logic, with thorough audit. Plug-ins that lazily run as system because "it's easier" accumulate security debt. The discipline to do impersonation right is a sign of security-conscious engineering; the absence of that discipline is a sign of accidental privilege escalation. For security-sensitive Dataverse deployments, periodic review of plug-in impersonation usage is essential.

Related guides