Dataverse Security Laboratory: Privileges, Ownership, Business Units, Teams, and Record-Level Authorization

Engineering and testing Microsoft Dataverse security through C#, security roles, business units, teams, record ownership, sharing, and the effective authorization model.

Power Platform Engineering Academy — Five Years in Five Days

Application: APP-010 — Dataverse Security Lab
Technical domain: Microsoft Dataverse security architecture
Technologies: C#, Dataverse SDK, Microsoft Entra ID, security roles, business units, owner teams, access teams, sharing, Model-Driven Apps
Status: Pre-implementation engineering design — experiments not yet executed


Introduction

Security in Microsoft Dataverse is not simply a question of whether a user has permission to open an application.

A user may have access to a Model-Driven App but lack permission to read a particular table. Another user may have permission to read the table but only see records owned by themselves or their team.

A third user may gain access to an individual record through sharing, even though they do not own it.

These outcomes are governed by multiple interacting security mechanisms.

Dataverse combines table privileges, privilege depth, record ownership, business units, security roles, teams, and record-level access rights.

This creates a powerful authorization model, but it also introduces complexity.

A developer who tests every operation using a System Administrator account can easily miss security defects that appear when the application is used by ordinary business users.

APP-010 — Dataverse Security Laboratory investigates the effective authorization model through controlled users, teams, records, SDK operations, and a Model-Driven App.

Our central engineering question is:

How does Dataverse determine whether an identity can perform a particular operation on a particular record, and how can engineers verify that decision?

1. Authentication Is Not Authorization

Authentication establishes the identity making a request.

Authorization determines what that identity is allowed to do.

For example, a C# application may successfully authenticate to Dataverse through Microsoft Entra ID.

That does not mean the authenticated identity can create, read, update, or delete every Dataverse record.

The effective authorization depends on the Dataverse security configuration and the requested operation.

A useful conceptual model is:

Microsoft Entra ID
│
▼
Authenticated Identity
│
▼
Dataverse User / Application User
│
▼
Security Roles + Teams + Ownership + Sharing
│
▼
Effective Access Evaluation
│
▼
Operation Allowed or Rejected

This model is simplified.

Actual access evaluation also depends on table type, privilege requirements, hierarchy security where configured, and other applicable platform security mechanisms.

The laboratory will isolate the principal mechanisms before combining them.

2. Security Roles and Privileges

Security roles define collections of privileges.

Common table privileges include:

PrivilegePurpose
CreateCreate records
ReadRead records
WriteUpdate records
DeleteDelete records
AppendAssociate a record with another record
Append ToAllow another record to be associated with this record
AssignChange record ownership
ShareGrant supported record-level access

Privileges are not interchangeable.

For example, permission to read a record does not imply permission to update it.

Similarly, having Write privilege does not automatically grant permission to assign ownership.

A developer must evaluate the privileges required by the actual operation.

Reference: Security roles and privileges.

3. Privilege Depth

For applicable owner-owned tables, privileges can be configured with different access depths.

Access depthMeaning
User / BasicRecords accessible through the user’s applicable ownership and access context
Business Unit / LocalRecords within the relevant business unit scope
Parent Business Units / DeepRecords in the business unit and subordinate units
Organization / GlobalRecords throughout the organization

Privilege depth determines the scope of a privilege.

It does not replace the privilege itself.

For example, Organization-level Read does not imply Organization-level Write.

A user can have broad visibility while retaining limited modification rights.

Dataverse also supports modernized business-unit security configurations, so ownership and role assignment should not be reduced to a simplistic assumption that every user belongs to exactly one effective security scope.

The laboratory must record the environment’s business-unit security configuration before interpreting results.

4. Record Ownership

Dataverse supports different table ownership models.

Two important categories are:

User or team-owned tables: Records can be owned by users or eligible teams, and owner-based security is applicable.

Organization-owned tables: Records do not use individual user/team ownership for access in the same way.

The ownership model is selected when the table is created and has significant architectural consequences.

For APP-010, the principal test table will be user or team-owned.

This allows the laboratory to investigate record ownership, reassignment, and team-based access.

5. Business Units

Business units provide an organizational security structure.

Consider this simplified hierarchy:

Organization
│
└── Headquarters
├── Engineering
│ ├── Platform Team
│ └── Integration Team
│
└── Operations
├── Support Team
└── Audit Team

Business units can influence the scope of privileges and record access.

However, the hierarchy itself does not grant every user access to all records beneath a particular node.

Effective access depends on assigned roles, privilege depths, ownership, team membership, and the applicable security configuration.

The laboratory will use separate identities and records to verify access across business-unit boundaries.

6. Owner Teams Versus Access Teams

Dataverse supports different team models.

6.1 Owner teams

Owner teams can own records.

Security roles can be assigned to owner teams, subject to the platform’s supported configuration.

This makes them useful when a group of users jointly owns business records.

6.2 Access teams

Access teams are designed to provide record-level collaboration.

They do not function as record owners in the same way as owner teams.

Access teams are commonly used when multiple users need access to particular records without changing ownership.

6.3 Engineering comparison

DimensionOwner teamAccess team
Can own recordsYesNo
Can be assigned security rolesYesNo
Supports collaborative record accessYesYes
Primary mechanismOwnership and role-based accessRecord-level access
Typical scenarioShared operational responsibilityTemporary or targeted collaboration

The laboratory will compare owner-team access with explicitly shared record access.

Reference: Manage Dataverse teams.

7. Record Sharing

Dataverse supports explicit sharing of records.

Sharing grants supported access rights to a user or team for a particular record.

For example, a record owner may share a record with another user and grant Read access.

The recipient may then read the record without becoming its owner.

However, sharing does not bypass every other security requirement.

The recipient must have the relevant table privileges and any other required permissions.

This distinction is critical.

A share is not a substitute for the underlying security role privileges.

The laboratory will test this explicitly.

8. Application Architecture

APP-010 Dataverse Security Laboratory
│
├── C# Security Test Runner
│ ├── Identity Verification
│ ├── Create / Read / Update / Delete
│ ├── Ownership Tests
│ ├── Assign Tests
│ ├── Sharing Tests
│ ├── Access Inspection
│ └── Authorization Diagnostics
│
├── Dataverse
│ ├── pea_securerecord
│ ├── pea_securityscenario
│ └── pea_securityexecution
│
├── Security Configuration
│ ├── Test Users
│ ├── Business Units
│ ├── Security Roles
│ ├── Owner Teams
│ └── Access Teams
│
└── Model-Driven App
├── Entry Dashboard
├── Secure Records
├── Security Scenarios
├── Execution Results
└── Access Diagnostics

The C# runner performs controlled operations under different identities.

The Model-Driven App provides the operational interface for inspecting records and security results.

9. Dataverse Data Model

9.1 Secure Record

Logical name: pea_securerecord

Ownership: User or team-owned

ColumnTypePurpose
pea_namePrimary nameRecord identifier
pea_externalcodeSingle line of textExperiment correlation
pea_classificationChoiceExample classification
pea_descriptionMultiple lines of textTest content
pea_amountDecimal numberUpdate test
pea_scenarioidSingle line of textScenario correlation

The classification field is initially informational.

It does not automatically enforce field-level security.

If field-level security is required, it must be configured explicitly using supported column security mechanisms.

9.2 Security Scenario

Logical name: pea_securityscenario

ColumnTypePurpose
pea_namePrimary nameScenario identifier
pea_operationSingle line of textRequested operation
pea_identitySingle line of textTest identity
pea_expectedaccessYes/NoExpected authorization
pea_descriptionMultiple lines of textScenario objective
pea_enabledYes/NoScenario availability

9.3 Security Execution

Logical name: pea_securityexecution

ColumnTypePurpose
pea_namePrimary nameExecution identifier
pea_scenarioSingle line of textScenario
pea_identitySingle line of textExecuting identity
pea_operationSingle line of textRequested operation
pea_recordidSingle line of textTarget record
pea_expectedaccessYes/NoExpected outcome
pea_actualaccessYes/NoObserved authorization
pea_passedYes/NoAssertion result
pea_messageMultiple lines of textDiagnostic details
pea_executedonDate and timeExecution timestamp

Security test results should be written by a trusted diagnostic identity.

A restricted test user may not have permission to create diagnostic records.

This is intentional: the test harness must not grant additional privileges merely to make logging easier.

10. Controlled Test Identities

The laboratory should define at least four identities.

IdentityIntended role
Security AdministratorConfigure roles, teams, and test records
Engineering UserOwn and modify selected records
Operations UserAccess records within an assigned scope
External CollaboratorReceive explicit record-level sharing

These identities must be configured with known roles and privileges.

The experiment should document each identity’s business unit, team memberships, and assigned roles.

Otherwise, unexpected access results may be caused by hidden privilege inheritance or additional role assignments.

The test identities should be dedicated to the laboratory rather than reusing production users with complex security configurations.

11. Inspecting Effective Access

The SDK provides specialized messages for inspecting record access.

One important request is:

RetrievePrincipalAccessRequest

This request retrieves the access rights a specified principal has to a record.

Example:

var request = new RetrievePrincipalAccessRequest
{
Principal = new EntityReference(
"systemuser",
userId),
Target = new EntityReference(
"pea_securerecord",
recordId)
};
var response =
(RetrievePrincipalAccessResponse)
service.Execute(request);
AccessRights rights = response.AccessRights;

The returned rights provide a useful diagnostic signal.

However, the test harness should still execute the actual operation under the target identity.

An access-inspection result is not a replacement for end-to-end authorization testing.

12. Granting Record Access

The SDK supports record sharing through GrantAccessRequest.

var request = new GrantAccessRequest
{
Target = new EntityReference(
"pea_securerecord",
recordId),
PrincipalAccess = new PrincipalAccess
{
Principal = new EntityReference(
"systemuser",
collaboratorId),
AccessMask = AccessRights.ReadAccess
}
};
service.Execute(request);

The operation grants the specified record-level access rights, subject to the caller’s privileges and platform rules.

After sharing, the laboratory should verify whether the collaborator can retrieve the record.

It should also test whether the collaborator can update the record.

If only Read access was granted and no other mechanism supplies Write access, the update should be rejected.

13. Revoking Record Access

Dataverse supports revoking previously granted access.

var request = new RevokeAccessRequest
{
Target = new EntityReference(
"pea_securerecord",
recordId),
Revokee = new EntityReference(
"systemuser",
collaboratorId)
};
service.Execute(request);

After revocation, the test harness should repeat the access checks.

However, revoking one explicit share does not guarantee that the user loses all access.

The user may still have access through ownership, security roles, team membership, or another applicable mechanism.

This is a central lesson of the laboratory:

Effective access can have multiple independent sources.

14. Assigning Record Ownership

Ownership can be changed using supported Dataverse operations.

For example, an SDK update can set ownerid to an eligible user or owner team.

var record = new Entity(
"pea_securerecord",
recordId);
record["ownerid"] = new EntityReference(
"systemuser",
newOwnerId);
service.Update(record);

The operation requires appropriate privileges and must respect the platform’s ownership rules.

Changing ownership can alter who can access the record.

It may also interact with business-unit security and related-record behavior.

The laboratory should inspect access before and after reassignment.

15. Independent C# Security Test Harness

The proposed project is:

PowerPlatformEngineeringAcademy/
└── Dataverse/
└── APP010.DataverseSecurityLab/
├── APP010.DataverseSecurityLab.csproj
└── Program.cs

Create the project:

dotnet new console --name APP010.DataverseSecurityLab
cd APP010.DataverseSecurityLab
dotnet add package Microsoft.PowerPlatform.Dataverse.Client

The initial experiment will use two Dataverse connections:

Administrative connection: Creates test records, configures sharing, inspects access, and persists diagnostics.

Restricted connection: Executes read and update operations under the target test identity.

The connections must authenticate as genuinely different Dataverse identities.

Changing a label in the C# application does not change the effective security principal.

The first executable experiment will:

  1. Authenticate both identities.
  2. Verify their user IDs.
  3. Create a test record under the administrative identity.
  4. Attempt retrieval under the restricted identity.
  5. Grant explicit Read access.
  6. Repeat the retrieval.
  7. Attempt an update.
  8. Revoke explicit sharing.
  9. Repeat the retrieval.
  10. Persist diagnostic results.

The actual outcome depends on the configured roles and ownership.

The harness must not assume that sharing is the only possible access mechanism.

16. Complete C# Security Test Runner

The following implementation exercises a controlled record-sharing scenario using two independently authenticated Dataverse identities.

It deliberately separates the administrator’s operations from the restricted user’s operations.

The restricted identity must have table-level Read privilege at an appropriate depth, but should initially lack access to the administrator-owned test record. Microsoft documents that record sharing cannot grant privileges the recipient does not have on the table. <Cite refs={[“turn848315search0″,”turn848315search3”]}/>

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
const string RecordTable = "pea_securerecord";
const string ExecutionTable = "pea_securityexecution";
string Required(string name) =>
Environment.GetEnvironmentVariable(name)
?? throw new InvalidOperationException(
$"Missing environment variable: {name}");
using var admin = new ServiceClient(
Required("DATAVERSE_ADMIN_CONNECTION"));
using var restricted = new ServiceClient(
Required("DATAVERSE_RESTRICTED_CONNECTION"));
if (!admin.IsReady || !restricted.IsReady)
{
throw new InvalidOperationException(
$"Connection failure. Admin: {admin.LastError}; " +
$"Restricted: {restricted.LastError}");
}
IOrganizationService adminService = admin;
IOrganizationService restrictedService = restricted;
Guid adminId = ((WhoAmIResponse)adminService.Execute(
new WhoAmIRequest())).UserId;
Guid restrictedId = ((WhoAmIResponse)
restrictedService.Execute(
new WhoAmIRequest())).UserId;
if (adminId == restrictedId)
{
throw new InvalidOperationException(
"Test identities must be different.");
}
Console.WriteLine($"Administrator: {adminId}");
Console.WriteLine($"Restricted user: {restrictedId}");
string scenarioId = $"APP010-{Guid.NewGuid():N}";
var record = new Entity(RecordTable)
{
["pea_name"] = "Security Laboratory",
["pea_externalcode"] = scenarioId,
["pea_description"] = "Controlled sharing experiment",
["pea_amount"] = 100m,
["pea_scenarioid"] = scenarioId,
["ownerid"] = new EntityReference(
"systemuser", adminId)
};
Guid recordId = adminService.Create(record);
var target = new EntityReference(
RecordTable, recordId);
var restrictedPrincipal = new EntityReference(
"systemuser", restrictedId);
void LogResult(
string scenario,
string operation,
bool expectedAccess,
bool actualAccess,
string message)
{
var log = new Entity(ExecutionTable)
{
["pea_name"] = $"APP010-{Guid.NewGuid():N}",
["pea_scenario"] = scenario,
["pea_identity"] = restrictedId.ToString(),
["pea_operation"] = operation,
["pea_recordid"] = recordId.ToString(),
["pea_expectedaccess"] = expectedAccess,
["pea_actualaccess"] = actualAccess,
["pea_passed"] = expectedAccess == actualAccess,
["pea_message"] = message,
["pea_executedon"] = DateTime.UtcNow
};
adminService.Create(log);
}
bool CanRead(string scenario, bool expected)
{
bool allowed = false;
string message;
try
{
restrictedService.Retrieve(
RecordTable,
recordId,
new ColumnSet("pea_name"));
allowed = true;
message = "Retrieve succeeded";
}
catch (FaultException<OrganizationServiceFault> ex)
{
message =
$"Dataverse fault {ex.Detail.ErrorCode}: " +
ex.Detail.Message;
}
LogResult(
scenario,
"Retrieve",
expected,
allowed,
message);
Console.WriteLine(
$"{scenario}: Read={allowed}, Expected={expected}");
if (allowed != expected)
{
throw new InvalidOperationException(
$"Unexpected read access in {scenario}");
}
return allowed;
}
// BASELINE: no access expected.
CanRead("BeforeSharing", expected: false);
// GRANT READ ACCESS
adminService.Execute(new GrantAccessRequest
{
Target = target,
PrincipalAccess = new PrincipalAccess
{
Principal = restrictedPrincipal,
AccessMask = AccessRights.ReadAccess
}
});
// Verify effective rights.
var accessResponse =
(RetrievePrincipalAccessResponse)
adminService.Execute(
new RetrievePrincipalAccessRequest
{
Principal = restrictedPrincipal,
Target = target
});
Console.WriteLine(
$"Effective rights: {accessResponse.AccessRights}");
// Read should now succeed.
CanRead("AfterSharing", expected: true);
// UPDATE SHOULD BE DENIED
bool writeAllowed = false;
string writeMessage;
try
{
var update = new Entity(RecordTable, recordId)
{
["pea_amount"] = 500m
};
restrictedService.Update(update);
writeAllowed = true;
writeMessage = "Update succeeded";
}
catch (FaultException<OrganizationServiceFault> ex)
{
writeMessage =
$"Dataverse fault {ex.Detail.ErrorCode}: " +
ex.Detail.Message;
}
LogResult(
"ReadOnlyShare",
"Update",
expectedAccess: false,
actualAccess: writeAllowed,
message: writeMessage);
if (writeAllowed)
{
throw new InvalidOperationException(
"Restricted user unexpectedly updated the record.");
}
// REVOKE EXPLICIT SHARING
adminService.Execute(new RevokeAccessRequest
{
Target = target,
Revokee = restrictedPrincipal
});
// Read should again be denied.
CanRead("AfterRevocation", expected: false);
Console.WriteLine(
"Security laboratory completed.");

16.1 Expected observations

ScenarioReadWrite
Before sharingDeniedNot tested
After Read sharingAllowedDenied
After revocationDeniedNot tested

These results require the prescribed security configuration. They are not universal outcomes for every Dataverse environment.

If the restricted user already has access through a broader security role or team membership, revoking an explicit share will not necessarily remove access.

The harness intentionally fails when observed access differs from the expected baseline.

16.2 Implementation limitations

The sample catches Dataverse service faults, but a production test harness should distinguish authorization failures from unrelated failures such as invalid metadata, connection problems, or unavailable services.

It should also verify that the restricted identity has the expected security roles before running.

The example does not automatically create users, teams, business units, or security roles.

Those components must be configured before execution.

17. Effective Access Is Additive

One of the most important Dataverse security principles is that access can be granted through multiple mechanisms.

For example:

User
│
├── Direct Security Roles
│
├── Team Security Roles
│
├── Record Ownership
│
├── Team Ownership
│
├── Explicit Sharing
│
└── Other Applicable Security Mechanisms
│
▼
Effective Access

Dataverse evaluates the applicable access mechanisms rather than using a simple deny-overrides-allow model for ordinary record permissions.

A user may have access through several independent paths.

Removing one path does not necessarily eliminate access.

Microsoft documents the effective privilege model and the relevant access mechanisms. <Cite refs={[“turn848315search1″,”turn848315search14”]}/>

18. Security Roles Versus Record Sharing

Security roles and record sharing solve different problems.

ConcernSecurity roleRecord sharing
ScopeTable privileges and access depthParticular records
Typical administrationSecurity administratorsAuthorized record collaborators
Defines table-level privilegeYesNo
Grants record-specific accessThrough applicable scopeYes
Can replace required table privilegeNot applicableNo
Primary purposeBaseline authorizationTargeted collaboration

A secure architecture should establish appropriate baseline privileges through roles.

Record sharing should be used where individual-record collaboration is required.

Excessive sharing can make effective access harder to reason about and maintain.

19. Column-Level Security

Dataverse also supports column-level security for eligible columns.

A user may have permission to read a record but not permission to read a particular secured column.

This is a different authorization dimension from record ownership and sharing.

For example, a user might be allowed to read a customer record while being restricted from viewing a sensitive financial field.

Column security requires explicit configuration and supported column types.

The laboratory should introduce a secured column in a later experiment and compare:

  1. Record access without secured-column access.
  2. Record access with secured-column Read permission.
  3. Record access with secured-column Update permission.

The Model-Driven App must not be treated as the security boundary.

Hiding a field from a form is not equivalent to securing it at the Dataverse service layer.

20. Security and the Model-Driven App

The Model-Driven App is an interface to Dataverse.

It does not replace Dataverse authorization.

Removing a table from navigation does not necessarily prevent an authorized user from accessing the table through another supported client or API.

Similarly, hiding a command does not necessarily prevent a user from performing the underlying operation through the SDK or Web API.

The laboratory must therefore test both:

User interface behavior: What does the user see and what actions are available?

Server authorization: Which operations does Dataverse actually permit?

A secure implementation requires both appropriate UI behavior and enforced server-side permissions.

21. Model-Driven App: PEA Dataverse Security Laboratory

The operational application will be named:

PEA Dataverse Security Laboratory

Entry dashboard

MetricPurpose
Total security testsNumber of recorded authorization checks
Passed assertionsExpected access matched actual access
Failed assertionsUnexpected authorization outcomes
Denied operationsNumber of rejected operations
Unexpected grantsOperations allowed when denial was expected
Latest executionMost recent security test

Secure Records

A view exposes test records, ownership, classification, and scenario identifiers.

Security Scenarios

A form documents the expected operation, target identity, and authorization result.

Security Executions

A view displays expected access, observed access, assertion outcome, and diagnostic information.

Access Diagnostics

A custom page may later display the effective rights returned by RetrievePrincipalAccessRequest alongside the actual result of an operation performed under the target identity.

The dashboard should make unexpected grants immediately visible.

An unexpected authorization success can be more dangerous than a denied operation.

22. Failure Injection Matrix

ExperimentExpected observation
User without table Read privilegeRecord retrieval denied
User with Read but insufficient record scopeRecord retrieval denied
User with explicit Read shareRetrieval allowed when baseline privilege exists
User with Read share but no Write accessUpdate denied
Revoke explicit shareAccess removed only if no other path remains
Assign record to another userOwnership and effective access may change
Add user to owner teamTeam-based access may become available
Remove user from owner teamTeam-derived access may be removed
Grant Organization-level ReadBroad record visibility
Secure a columnRecord access does not automatically grant column access
Hide a form fieldDoes not enforce server-side authorization
Use an application userPermissions follow the application’s Dataverse security configuration

Each experiment should record the security configuration before execution.

Without that evidence, a failed assertion may be difficult to explain.

23. Architectural Lessons

APP-010 establishes several important engineering principles.

Authentication and authorization are separate. A valid token does not grant unrestricted Dataverse access.

Privileges and privilege depth are different dimensions. The ability to perform an operation must be evaluated together with the applicable record scope.

Record access can have multiple sources. Ownership, roles, teams, and sharing can combine.

Sharing does not replace baseline privileges. A user must have the necessary table privilege.

UI restrictions are not server-side security. Hidden fields and commands do not substitute for Dataverse authorization.

Security testing requires multiple identities. Testing exclusively as System Administrator conceals important defects.

Unexpected access is a critical test failure. A security laboratory must treat unintended authorization as seriously as functional errors.

24. Microsoft Learn Technical References

  1. Security concepts for developers — Privileges, access levels, and effective roles.
  2. Security and data access — Dataverse security architecture.
  3. Data operations and access rights — Privileges required by operations.
  4. Sharing and assigning — GrantAccess, ModifyAccess, RevokeAccess, and assignment.
  5. Verifying access in code — Access inspection through SDK and Web API.
  6. Access teams and owner teams — Team collaboration and ownership.
  7. Manage Dataverse teams — Team administration.
  8. Security roles and privileges — Security role configuration.

Conclusion

Dataverse security is a layered authorization system.

The effective ability to perform an operation depends on the requested privilege, applicable access depth, ownership, security roles, team membership, sharing, and other relevant platform mechanisms.

A Model-Driven App can present or hide operations, but the underlying security boundary is enforced by Dataverse.

The most reliable way to understand this model is to test it under controlled identities and inspect actual service responses.

The central engineering principle is:

Security must be verified through effective permissions and real operations, not inferred from interface visibility or role names.

APP-010 establishes the foundation for advanced experiments involving plug-in impersonation, Custom APIs, application users, integration identities, and enterprise security architecture.


Power Platform Engineering Academy — Five Years in Five Days

Article 010/100 — Dataverse Security Laboratory

Identify the principal. Inspect the privilege. Execute the operation. Verify effective access.

Edvaldo Guimrães Filho Avatar

Published by