Skip to content

Permissions Reference

Sebastian F. Markdanner [MVP] edited this page May 11, 2026 · 2 revisions

Every API call the portal makes uses delegated permissions — that is, the signed-in user's permissions, not application permissions. There are no client secrets, no service principal credentials, and no app-only permissions anywhere in the codebase or in deployed resources.

Scopes requested at sign-in

Scope Plane Purpose Minimum role to consent
openid, profile, email, offline_access Microsoft identity platform Standard sign-in scopes User can self-consent
User.Read Microsoft Graph Read signed-in user profile and ID User can self-consent
RoleManagement.ReadWrite.Directory Microsoft Graph List Entra ID role eligibilities; activate / deactivate Privileged Role Administrator or Global Administrator
PrivilegedAccess.ReadWrite.AzureADGroup Microsoft Graph Activate / deactivate PIM for Groups (member and owner access) Privileged Role Administrator or Global Administrator
RoleManagementPolicy.Read.AzureADGroup Microsoft Graph Read PIM for Groups policy settings (the policy matrix) Privileged Role Administrator or Global Administrator
Policy.Read.All Microsoft Graph Read role-management policy assignments and Conditional Access policies for auth-context detection Application Administrator or Global Administrator
AdministrativeUnit.Read.All Microsoft Graph Resolve Administrative Unit display names for AU-scoped Entra roles Privileged Role Administrator or Global Administrator
AuditLog.Read.All Microsoft Graph Read audit logs to surface activation history Security Reader, Reports Reader, or Global Administrator
https://management.azure.com/user_impersonation Azure Resource Manager Activate / deactivate Azure Resource PIM roles User can self-consent

What "minimum role to consent" means

Consenting to the application (allowing the application to ask for the scope) is different from being able to use the scope. A regular user can sign in and the app will work for any role they personally have an eligibility for.

Some scopes (Policy.Read.All, AdministrativeUnit.Read.All, AuditLog.Read.All, RoleManagement.ReadWrite.Directory, PrivilegedAccess.ReadWrite.AzureADGroup, RoleManagementPolicy.Read.AzureADGroup) require admin consent on most tenants because they grant access beyond the user's own data. If your tenant restricts user consent, an administrator must grant tenant-wide admin consent before users can sign in.

The self-hosted Bicep template emits an adminConsentUrl that takes you straight to the right consent endpoint for your app registration.

Why those specific scopes?

  • RoleManagement.ReadWrite.Directory is the umbrella scope for Entra role eligibilities and assignments — both reads (*Schedule*Instances) and writes (activate / deactivate). The portal uses the broader RoleManagement.ReadWrite.Directory instead of separate RoleEligibilitySchedule.Read.Directory + RoleAssignmentSchedule.ReadWrite.Directory so that one consent covers the entire activation workflow.
  • Policy.Read.All is required because the portal renders the per-role policy matrix and detects auth-context requirements before submit. Without it, every activation attempt would have to round-trip with claims challenges to discover policy.
  • AdministrativeUnit.Read.All lets the portal display the AU name under AU-scoped roles instead of an opaque GUID.
  • AuditLog.Read.All powers the activity history surface.
  • https://management.azure.com/user_impersonation is the standard delegated scope for Azure Resource Manager. It does not grant any specific resource access by itself — the user still needs an Azure Resource PIM eligibility to actually activate anything.

Scopes the portal does not request

The portal deliberately avoids:

  • Application permissions of any kind
  • Directory.AccessAsUser.All or similar broad delegated scopes
  • Mail, calendar, or files scopes
  • User.ReadWrite* or directory-wide write scopes other than the role-management ones above

If you ever see the portal request a scope outside this list, it's a bug — please open an issue.

Clone this wiki locally