Dataverse-Native Security Setup
Preview
This security model is currently in preview — both Microsoft's underlying unified Dataverse security feature and Power Portals Pro's support for it. Power Portals Pro follows Microsoft's release schedule: once the feature reaches general availability from Microsoft, Power Portals Pro's support will leave preview as well. The preview designation exists to account for any changes Microsoft may make on its side during the preview phase.
The Dataverse-native security model lets Dataverse itself enforce security for your portal users through standard security roles, configured exactly the way Power Pages configures them — web roles and table permissions. This page walks through the complete setup, end to end.
For how the model works and how it relates to permission handlers, see the Security overview
1. Install the Power Pages Framework Components
The unified security model runs on components Microsoft installs into your Dataverse environment when a Power Pages website is created. If the environment has never hosted a Power Pages site, create one now — any template works, and a trial site is fine. See Create and manage sites in the Power Pages documentation.
Note
You do not need to pay for the site or keep it running — after the framework components are installed and the security feature is enabled, you can delete the website itself. The Power Pages site record (
powerpagesite) referenced by your configuration must remain in the environment, since user mappings and security-role sync resolve against it.
2. Enable Unified Dataverse Security for the Site
Enable Microsoft's unified Dataverse security feature for the site by following the steps in Unify Power Pages security with Dataverse. Once enabled, the platform creates a paired Dataverse security role (named PowerPages_*) for each web role on the site and keeps it in sync.
3. Configure Web Roles and Table Permissions
In the Power Pages Management app, create (or adjust) the site's web roles and table permissions, and link each table permission to the web roles that should receive it. This is the only supported way to grant access under this model — the platform translates the linked table permissions into privileges on each web role's synced security role. Scopes work exactly as in Power Pages (Global, Contact, Account, ...), so record-level access rules are configured here too.
4. Find Your Power Pages Site Id
PowerPortalsPro needs the id of the site's powerpagesite record. You can query it directly — for example, open <your org url>/api/data/v9.2/powerpagesites?$select=name in a browser and copy the powerpagesiteid of your site.
5. Enable Provisioning in Power Portals Pro
Configure SecurityOptions in your server's Program.cs:
builder.Services.Configure<SecurityOptions>(options =>
{
options.DataverseSecurity.ProvisionSystemUsers = true;
options.DataverseSecurity.PowerPagesSiteId = new Guid("<your powerpagesite id>");
});
The configuration is validated at startup — when ProvisionSystemUsers is enabled, PowerPagesSiteId must be set and must resolve to an existing powerpagesite record, otherwise the application fails to start with guidance. From this point on, PowerPortalsPro automatically provisions a system-managed (C2) systemuser and a powerpagesusermapping record for every portal contact — at registration for new contacts, and lazily at sign-in for existing ones — and impersonates that user on every Dataverse call.
6. Assign Web Roles to Contacts
Grant access to individual users by assigning web roles to their contacts — in the Power Pages Management app, or programmatically through the powerpagecomponent_mspp_webrole_contact relationship. The platform assigns and removes the synced security roles automatically as web-role membership changes.
Tip
Dataverse caches each user's effective privileges per server node, so role and privilege changes can take from a few seconds up to a couple of minutes to take effect after an assignment. Account for this in tests and in any flow that grants access and then immediately acts on it.
Anonymous Visitors
Signed-out visitors are covered by the same model. Power Pages automatically creates an Anonymous user for the site — a system-managed user with the identity PowerPages_00000000-0000-0000-0000-000000000000@<site id>.com — and PowerPortalsPro impersonates it for every unauthenticated request. Grant anonymous access the Power Pages way: mark a web role as the site's Anonymous Users role in the Power Pages Management app and link table permissions to it; the synced security role then governs what signed-out visitors can see.
Note
The Anonymous user is created lazily by Power Pages, so sites created before the unified security feature may not have one yet (it is discovered through the site's contact-less
powerpagesusermappingrecords — the user itself is invisible to attribute queries — and a candidate is only accepted after its identity is verified against the well-known Anonymous username). When it can't be found, anonymous visitors fall back to portal-side permission handlers — meaning no anonymous data access unless handlers are registered — and the framework logs the outcome at startup and keeps retrying periodically.
What About Permission Handlers?
Sessions under this model bypass ITablePermissionHandler / ITableRecordPermissionHandler entirely — exactly like internal systemuser sign-ins — because Dataverse enforces security natively through the impersonated user's roles. You don't need to write or register any permission-handler code. Handlers still apply to sessions that are not backed by an impersonated system user (the feature disabled, a session where provisioning failed and the framework fell back to portal-side security, or anonymous visitors on a site without the Anonymous user), so existing handler-based portals can migrate incrementally.
Distinguishing Provisioned Users in Your UI
Sessions carry a PortalUserType claim holding the integer value of the PortalUserType enum: Contact (classic portal user), SystemUser (real internal sign-in), or ContactStubUser (a contact backed by a provisioned system-managed user); ContactStubUser sessions additionally carry a SystemUserId claim with the provisioned user's id, resolved from the authoritative powerpagesusermapping record. The same enum is returned by GET /api/auth/me as CurrentUserInfo.PortalUserType. Use the GetPortalUserType() and GetDataverseSystemUserId() extensions on ClaimsPrincipal, and never present a ContactStubUser session as an internal user.
API Reference
DataverseSecurityOptions Class
Properties
Name | Type | Default | Description |
|---|---|---|---|
PowerPagesSiteId | Guid? | The id of the DataverseSecurityOptions.ProvisionSystemUsers is enabled — the mapping technically accepts a null site, but security-role sync does not function without one. | |
ProvisionSystemUsers | bool | False | When true, a system-managed (C2) DataverseSecurityOptions.PowerPagesSiteId; validated at application startup. |
PowerPagesSiteIdDataverseSecurityOptions.ProvisionSystemUsers is enabled — the mapping technically accepts a null site, but security-role sync does not function without one.ProvisionSystemUserstrue, a system-managed (C2) DataverseSecurityOptions.PowerPagesSiteId; validated at application startup.