Configuring App Registration Permission Scopes
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page 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.
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.
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
- Register the Web API: In the Entra ID portal, create a new App Registration for your API.
- 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>orhttps://api.yourdomain.com). This acts as the unique prefix for your scopes. - Add a Scope: Click "Add a scope." You will need to provide:
- Scope name: e.g.,
Orders.ReadorData.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.
- Scope name: e.g.,
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.
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.
- 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).
- Choose the Permission Type: Select either Delegated or Application.
- 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 useDirectory.Read.Alljust 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. |
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.
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.
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 (
scpclaim): These are about delegation. They represent what the user has allowed the application to do. "I allow this app to read my mail."Roles (
rolesclaim): 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.
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
scopeparameter 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.
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)
- Register App: "Profile-API".
- Expose an API: Set URI to
api://profile-api. - Add Scope:
Profile.Read. - API Permissions: Add Microsoft Graph -> Delegated ->
User.Read.All(to see managers). - Admin Consent: Since
User.Read.Allis sensitive, an admin must click "Grant admin consent."
Phase 2: The React Frontend (The Client)
- Register App: "Profile-Web-App".
- Authentication: Configure SPA redirect URIs.
- API Permissions: Add "APIs my organization uses" -> "Profile-API" ->
Profile.Read. - 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.
- The Frontend sends a token with the
Profile.Readscope to the Profile API. - The Profile API validates this token.
- The Profile API exchanges this token with Entra ID for a new token that has the
User.Read.Allscope for Microsoft Graph.
This architecture ensures that each layer has exactly the permissions it needs and nothing more.
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
scpclaim (delegated) or therolesclaim (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.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons