Share via

Entra ID Web API Authorization Model

ritmo2k 911 Reputation points
2026-06-18T21:42:45.54+00:00

I have an ASP.NET Core Web API that we host for use by other teams and services. I would appreciate guidance on how to design the permission model.

The long-term goal is to set up a public client and build tooling for users. We also plan to provision app registrations for automation that requires API access. The short-term focus is limited to app registrations.

We want to use security groups for fine-grained authorization because the API has too many permissions, and those permissions change too frequently, to manage effectively with scopes or app roles. Security groups also align well with the existing processes used to manage the data behind the API.

Given the pending interactive delegated permission model for the public client, and the non-interactive application permission model for service principals, am I missing anything by avoiding scopes and app roles entirely and relying only on a custom authorization policy handler in the Web API?

Microsoft Security | Microsoft Entra | Microsoft Entra ID
0 comments No comments

1 answer

Sort by: Most helpful
  1. AI answer

    2026-06-18T21:43:20.2833333+00:00

    Security groups and a custom authorization policy handler are valid and supported, but relying only on groups/app roles in the token and skipping scopes/app roles at the API surface loses important separation of concerns and flexibility.

    Key points from the Microsoft identity platform guidance:

    1. Web APIs are expected to expose scopes and app roles
      • Web APIs should publish at least one scope (delegated permission) and at least one app role (application permission) so client apps can obtain access tokens with appropriate permissions.
      • Example from the tutorial: delegated permissions like ToDoList.Read / ToDoList.ReadWrite and application permissions like ToDoList.Read.All / ToDoList.ReadWrite.All are defined and then enforced by the API.
      • When a client calls the API, only tokens with those scopes or app roles are authorized to access protected endpoints.
      This pattern is recommended even if additional fine-grained checks are implemented via groups or custom policies.
    2. Scopes vs app permissions map directly to your two client types
      • Scopes (delegated permissions) are for interactive/public clients acting on behalf of a user. They appear in scp/scope claims and are validated by the API.
      • App permissions (application permissions) are for daemon/service apps using client credentials. They appear as roles claims.
      • Microsoft.Identity.Web explicitly validates scopes and app permissions as part of authorization, in addition to signature, audience, and expiration.
      Designing scopes/app roles that represent coarse-grained capabilities (e.g., read vs write, standard vs full access) gives a clean contract between clients and the API. Fine-grained decisions can still be based on groups or other claims.
    3. Groups, admin roles, and app roles are first-class for policy-based authorization
      • ASP.NET Core authorization policies can use groups, wids (administrator roles), and role claims to authorize access to server APIs.
      • Example: a policy that requires a specific admin role via wids, then applied with [Authorize(Policy = "BillingAdministrator")] on a controller.
      • This is exactly the pattern used for group/role-based fine-grained authorization.
      So a custom authorization policy handler that inspects security groups is fully aligned with the platform, as long as the token contains the required claims.
    4. Best practice is to combine [Authorize] with scope/role validation and policies
      • Guidance recommends always pairing [Authorize] with explicit scope validation (for delegated access) and using policies for more complex rules.
      • Policies can combine scopes, roles, and arbitrary claims:
        • Example: a policy that requires a scope and a claim like department = IT.
      • Default policies can be set so that every [Authorize] implicitly requires a given scope.
      This model lets the API:
      • First enforce that the client has the right API-level permission (scope/app role).
      • Then apply fine-grained rules via groups/claims in policies.
    5. Least-privilege design is easier with scopes/app roles
      • Zero Trust guidance recommends defining multiple least-privilege delegated permissions instead of a single broad “access as user” permission.
      • Separate read vs write, standard vs full access, and create specific permissions per core scenario.
      • This helps prevent over-privileged clients and makes it easier to reason about what each client can do.
      If only security groups are used, the permission surface becomes implicit and harder to manage across tenants and client apps. Scopes/app roles give a clear, documented contract that complements group-based checks.
    6. What is lost by avoiding scopes/app roles entirely If only security groups and a custom policy handler are used:
      • There is no explicit API permission surface exposed in Entra ID for client app registrations. Client owners cannot easily see or request specific API permissions.
      • Delegated vs application access is not clearly modeled at the token level (beyond generic group membership), which can complicate future tooling and consent flows.
      • Standard patterns and tooling that expect scopes/app roles (e.g., consent UX, admin consent, least-privilege reviews) are not leveraged.
      • For public clients, the delegated permission story (scopes in scp) becomes non-standard, which can make future integration and governance harder.
      The custom policy handler can still enforce correct behavior, but it shifts more responsibility into custom code and away from the identity platform’s built-in permission model.
    7. Recommended model for the described scenario For the mix of public clients and daemon apps, and the desire for fine-grained group-based authorization:
      • Define a small set of scopes for user-delegated access (e.g., Api.Read, Api.Write, Api.Admin) and app roles for daemon access (e.g., Api.Read.All, Api.Write.All).
      • Use Microsoft.Identity.Web to validate scopes/app roles on incoming tokens.
      • Implement authorization policies that:
        • Require appropriate scopes/app roles, and
        • Check security group membership or other claims for fine-grained access.
      • For changing, fine-grained permissions, continue to use security groups and policies; for stable, coarse-grained capabilities, use scopes/app roles.
      This approach keeps the benefits of security groups and custom policy handlers while aligning with the platform’s recommended authorization model and least-privilege design.

    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.