Configuring App Registration Permission Scopes

Earn 25 points (50 with Pro) in two steps

  1. ① Read through the lesson — each section gets a ✓ as you scroll through it.
  2. ② When every section has a ✓, tap Complete lesson.

0 of 10 read · keep scrolling

✦ See fewer ads and earn double points — 50 a lesson instead of 25 — with Pro

Configuring App Registration Permission Scopes: A Comprehensive Guide

In the modern landscape of cloud computing, security isn't just about building a wall around your data; it’s about carefully managing who—and what—can interact with that data. When you build or integrate an application within Microsoft Entra ID (formerly Azure Active Directory), you aren't just writing code; you are participating in a complex ecosystem of identity and trust. At the heart of this ecosystem lies the concept of Permission Scopes.

Permission scopes are the "fine print" of application security. They define exactly what an application is allowed to do once it has been authenticated. Without properly configured scopes, an application might have too much power, leading to potential data breaches, or too little power, resulting in broken functionality. For identity professionals and developers, mastering scopes is the difference between a secure, scalable application and a security liability waiting to happen.

In this lesson, we will explore the mechanics of Microsoft Entra ID permission scopes. We will cover the differences between delegated and application permissions, how to expose your own APIs, the intricacies of the consent framework, and the best practices that keep your environment secure.


Not read yet

Understanding the Fundamentals of Scopes

Before we dive into the technical configuration, we need to establish a clear mental model of what a "scope" actually is. In the context of OAuth 2.0 and OpenID Connect (the protocols powering Entra ID), a scope is a way to limit an application's access to a user's data or a service's functionality.

Think of an application registration as a digital identity for your code. When that code wants to talk to an API—like Microsoft Graph to read a user’s calendar—it doesn't just ask for "access." Instead, it asks for a specific scope, such as Calendars.Read. The API then checks if the application (and the user using it) has been granted that specific permission before allowing the request to proceed.

The Two Pillars: Delegated vs. Application Permissions

One of the most common points of confusion for those new to Entra ID is the distinction between Delegated permissions and Application permissions. Choosing the wrong one can lead to significant security gaps or application failures.

Delegated Permissions

Delegated permissions are used when an application is acting on behalf of a signed-in user. In this scenario, the application’s effective permissions are the intersection of the permissions granted to the application and the permissions held by the user.

For example, if an app has the delegated permission Files.ReadWrite, but the signed-in user only has permission to read files in a specific SharePoint site, the app will not be able to write to those files. The app cannot exceed the authority of the user it is representing.

Application Permissions

Application permissions (sometimes called "App-only" or "Service" permissions) are used when an application runs without a signed-in user. These are common for background services, daemons, or scheduled tasks.

In this case, the application acts as its own identity. Because there is no user to provide a "ceiling" for the permissions, these are often considered higher risk. An application with the application permission Mail.Read can read the email of every user in the entire organization. Consequently, these almost always require an administrator's explicit approval.

Callout: The Effective Permissions Rule

Delegated Access: Effective Permissions = (App Permissions) AND (User Permissions). The application can never do more than the user is allowed to do.

Application Access: Effective Permissions = (App Permissions). The application has the full power of the roles assigned to it, regardless of which user (if any) is involved.


Not read yet

Defining and Exposing Your Own API Scopes

While Microsoft provides a wealth of pre-defined scopes for services like Graph, Outlook, and SharePoint, you will frequently need to create your own scopes for custom APIs you build. This process is known as "Exposing an API."

When you expose an API, you are essentially defining the "menu" of permissions that other applications can request from you.

Step-by-Step: Exposing a Custom Scope

  1. Register the Web API: In the Entra ID portal, create a new App Registration for your API.
  2. Set the Application ID URI: Navigate to the Expose an API blade. You must set an Application ID URI (usually in the format api://<client-id> or https://api.yourdomain.com). This acts as the unique prefix for your scopes.
  3. Add a Scope: Click "Add a scope." You will need to provide:
    • Scope name: e.g., Orders.Read or Data.Export.
    • Who can consent: Users and admins, or Admins only.
    • Display names and descriptions: These are shown to users during the consent process, so make them clear and descriptive.

Practical Example: The Inventory API

Imagine you are building an Inventory Management API. You might define the following scopes:

  • Inventory.View: Allows the app to see stock levels. (User consent allowed).
  • Inventory.Modify: Allows the app to change stock levels. (Admin consent required).
  • Inventory.AdminFullControl: Allows the app to delete entire warehouses from the database. (Admin consent required).

By breaking these down, you ensure that a simple reporting dashboard only requests Inventory.View, adhering to the principle of least privilege.


Not read yet

Requesting Permissions for Other APIs

Once an API has exposed its scopes, other applications (clients) can request them. This is done through the API Permissions blade in the Entra portal.

The Process of Adding Permissions

When you add a permission to an app registration, you are declaring what your application intends to use. It does not mean the application has those permissions yet; they must still be "consented" to.

  1. Select the API: You can choose from "Microsoft APIs" (like Graph), "APIs my organization uses" (your custom APIs), or "My APIs" (APIs registered in your own tenant).
  2. Choose the Permission Type: Select either Delegated or Application.
  3. Select the Scopes: Check the boxes for the specific permissions your code requires.

Note: Always start with the most restrictive permission possible. If your app only needs to read a user's name, use User.Read. Do not use Directory.Read.All just because it's easier to configure.

Comparison: Static vs. Dynamic Consent

Microsoft Entra ID supports two ways of requesting consent:

Feature Static Consent Dynamic Consent
Configuration Defined in the Azure Portal under API Permissions. Defined in the code via the scope parameter.
User Experience User sees all requested permissions at the first login. User sees only the permissions requested for a specific action.
Requirement Required for Application Permissions. Common for Delegated Permissions in multi-tenant apps.
Flexibility Lower; requires a portal update to change. Higher; can be changed in the code on the fly.

Not read yet

The Consent Framework

The consent framework is the mechanism that ensures users and administrators are aware of what an application is asking for. It is the "Are you sure?" dialog of the identity world.

User Consent

For non-sensitive permissions (like reading a user's basic profile), an individual user can often grant permission themselves. When they first log into the app, a prompt appears: "This app would like to read your profile. Do you accept?"

Admin Consent

Some permissions are too powerful for a standard user to approve. Anything that affects the entire tenant or accesses sensitive data (like User.Read.All or any Application Permission) requires an Administrator to step in.

An administrator can grant consent for the entire organization. This means that once the admin clicks "Grant admin consent for [Tenant]," individual users will no longer see the consent prompt for those specific permissions.

Warning: Be extremely cautious when granting tenant-wide admin consent. If an application is compromised, the attacker has immediate access to all data covered by those scopes across your entire organization.


Not read yet

Technical Implementation: Scopes in the Token

To truly understand scopes, we have to look at the JSON Web Token (JWT). When an application successfully authenticates and requests scopes, Entra ID issues an Access Token.

Inside this access token is a claim called scp (for delegated permissions) or roles (for application permissions).

Code Snippet: Validating Scopes in a Web API (C#/.NET)

If you are building an API, your code must check the incoming token to ensure the required scope is present. Here is a simplified example using the Microsoft Identity Web library:

[Authorize]
[RequiredScope("Inventory.View")] // This attribute checks the 'scp' claim
[HttpGet]
public IEnumerable<InventoryItem> Get()
{
    // If the 'scp' claim does not contain 'Inventory.View', 
    // the middleware returns a 403 Forbidden before this code runs.
    return _inventoryService.GetAllItems();
}

Code Snippet: Requesting Scopes in Python (MSAL)

When writing a client application using the Microsoft Authentication Library (MSAL), you specify the scopes in your acquisition call:

import msal

# Configuration details
app_id = 'your-client-id'
tenant_id = 'your-tenant-id'
authority = f"https://login.microsoftonline.com/{tenant_id}"
scopes = ["https://graph.microsoft.com/User.Read", "api://my-custom-api/Inventory.View"]

# Create the MSAL app instance
app = msal.PublicClientApplication(app_id, authority=authority)

# Request the token
result = app.acquire_token_interactive(scopes=scopes)

if "access_token" in result:
    print("Access token acquired successfully")
    # You can now use result['access_token'] to call your API
else:
    print(f"Error: {result.get('error_description')}")

In this example, the scopes list tells Entra ID exactly what the application is asking for. If the user hasn't consented to these yet, the acquire_token_interactive call will trigger the browser-based consent UI.


Not read yet

Best Practices for Configuring Scopes

Following industry standards ensures that your identity architecture remains resilient and secure. Here are the primary recommendations for managing scopes in Microsoft Entra ID.

1. The Principle of Least Privilege

This is the golden rule of security. Never request Directory.ReadWrite.All if User.Read is sufficient. By limiting the scope of access, you limit the "blast radius" if the application's credentials are stolen.

2. Use Meaningful Naming Conventions

When exposing your own APIs, use a Resource.Operation or Resource.Operation.Constraint format.

  • Good: Files.Read, Orders.Process, Reports.View.Department
  • Bad: Access_All, Permission1, ReadData

Clear names help both the developers consuming your API and the administrators who have to approve the permissions.

3. Avoid Overusing .default

The .default scope is a special keyword in Entra ID that requests all permissions statically configured in the app registration. While convenient, it bypasses the benefits of dynamic consent and can lead to "scope creep," where an app receives more permissions than it needs for a specific task. Use specific scope names whenever possible.

4. Regularly Audit Permissions

Applications evolve. A permission that was necessary three years ago might no longer be needed today. Use the "Workload identities" reports in the Entra admin center to see which applications are actually using the permissions they’ve been granted. If a permission hasn't been used in 90 days, remove it.

5. Separate Client and API Registrations

Even if you are building a single-page application (SPA) and its corresponding backend API, create two separate app registrations.

  • The API Registration: Defines the scopes (Expose an API).
  • The Client Registration: Requests the scopes (API Permissions). This separation allows you to manage the security posture of the "caller" and the "receiver" independently.

Callout: Scopes vs. Roles

Scopes (scp claim): These are about delegation. They represent what the user has allowed the application to do. "I allow this app to read my mail."

Roles (roles claim): These are about identity. They represent what the application itself (or the user) is allowed to do based on their position in the system. "This app is an Admin-level service."

Use Scopes for client-to-API interactions and Roles for application-level permissions or fine-grained internal authorization.


Not read yet

Common Pitfalls and How to Avoid Them

Even experienced architects run into trouble with scopes. Understanding these common mistakes will save you hours of troubleshooting.

The "403 Forbidden" Mystery

A common scenario: You've added the permission in the portal, granted admin consent, but the API still returns a 403 Forbidden.

  • The Cause: Often, the application hasn't requested the new scope in its code, or it is using a cached token that doesn't include the new claim.
  • The Fix: Ensure the scope parameter in your code includes the new permission and force a fresh login to clear old tokens.

Forgetting the Application ID URI

You cannot expose scopes until you have set the Application ID URI. If you try to add a scope and the option is greyed out or fails, check that you have defined the URI in the "Expose an API" blade.

Mixing v1.0 and v2.0 Scopes

Microsoft Entra ID has two versions of its authentication endpoints. The v1.0 endpoint uses "Resources" (a single URL for an entire API), while the v2.0 endpoint uses "Scopes" (individual permissions).

  • The Problem: Trying to request v1.0 resources using v2.0 scope syntax (or vice versa) leads to errors.
  • The Fix: Stick to the v2.0 endpoint and MSAL libraries, which are the current standard and handle scope-based logic correctly.

Consent Phishing

Attackers sometimes create malicious apps with names like "Office 365 Update" and request broad scopes like Mail.Read or Files.ReadWrite.All.

  • The Risk: Unsuspecting users might click "Accept," giving attackers access to their data.
  • The Defense: Implement Publisher Verification for your apps. This shows a "blue checkmark" in the consent dialog, proving the app comes from a verified organization. Additionally, configure user consent settings to require admin approval for all but the most basic permissions.

Not read yet

Step-by-Step: Configuring a Multi-Tier Application

Let's walk through a real-world scenario. You have a React Frontend that needs to call a Custom Profile API, which in turn needs to call Microsoft Graph to get the user's manager.

Phase 1: The Profile API (The Middle Tier)

  1. Register App: "Profile-API".
  2. Expose an API: Set URI to api://profile-api.
  3. Add Scope: Profile.Read.
  4. API Permissions: Add Microsoft Graph -> Delegated -> User.Read.All (to see managers).
  5. Admin Consent: Since User.Read.All is sensitive, an admin must click "Grant admin consent."

Phase 2: The React Frontend (The Client)

  1. Register App: "Profile-Web-App".
  2. Authentication: Configure SPA redirect URIs.
  3. API Permissions: Add "APIs my organization uses" -> "Profile-API" -> Profile.Read.
  4. Code: In the React app, use MSAL to request the scope api://profile-api/Profile.Read.

Phase 3: The Token Exchange (OBO Flow)

Since the Profile API needs to call Graph on behalf of the user who called it, it uses the On-Behalf-Of (OBO) flow.

  1. The Frontend sends a token with the Profile.Read scope to the Profile API.
  2. The Profile API validates this token.
  3. The Profile API exchanges this token with Entra ID for a new token that has the User.Read.All scope for Microsoft Graph.

This architecture ensures that each layer has exactly the permissions it needs and nothing more.


Not read yet

Quick Reference: Permission Troubleshooting

Issue Likely Cause Resolution
User sees "Need admin approval" Scope requires Admin Consent. Have a Global Admin or Privileged Role Admin grant consent in the portal.
scp claim missing in token Permissions are "Application" type, not "Delegated". Check the roles claim instead, or change permission type.
"Invalid Scope" error Typo in scope name or wrong App ID URI. Verify the scope string matches exactly what is in the "Expose an API" blade.
New permissions not showing up Cached tokens. Sign out and sign back in to force a new token issuance.
Consent screen shows "Unverified" Missing Publisher Verification. Complete the MPN (Microsoft Partner Network) verification process.

Conclusion

Configuring app registration permission scopes is more than a configuration task; it is a fundamental security practice. By understanding the nuances between delegated and application permissions, learning how to properly expose and request scopes, and respecting the consent framework, you build applications that are not only functional but also trustworthy.

The landscape of identity is constantly shifting, but the principle of least privilege remains constant. As you move forward, treat every permission request as a potential risk and every scope definition as a boundary that protects your organization's most valuable asset: its data.

Key Takeaways

  • Delegated permissions are for apps acting as a user; Application permissions are for background services acting as themselves.
  • Effective permissions for delegated access are always the intersection of the app's scopes and the user's own rights.
  • Exposing an API requires setting an Application ID URI and defining specific, granular scopes to follow the principle of least privilege.
  • Admin consent is mandatory for all Application permissions and sensitive Delegated permissions to prevent unauthorized data access.
  • JWT tokens carry scopes in the scp claim (delegated) or the roles claim (application); APIs must be coded to validate these claims.
  • Static consent is configured in the portal, while dynamic consent is handled in code, offering more flexibility for modern applications.
  • Regular audits of granted permissions are essential to prevent "scope creep" and maintain a clean, secure identity environment.

Not read yet

Each section gets a ✓ as you scroll through it. Tap the button to jump to the next one.