I am creating an Azure AD app and noticed there are two permissions types, Application Permissions and Delegated Permissions. What is the difference between the two and under what scenario should I use them?
You typically use delegated permissions when you want to call the Web API as the logged on user. Say for example that the Web API needs to filter the data it returns based on who the user is, or execute some action as the logged in user. Or even just to log which user was initiating the call.
Application permissions are used when the application calls the API as itself. For example to get the weather forecast for a certain zipcode (it does not matter which user is logged on). The client can even call the API when there's no user present (some background service calling the API to update some status).
From the documentation here: Configure a client application to access web APIs:
Application Permissions: Your application needs to access the web API directly as itself (no user context). This type of permission
requires administrator consent and is also not available for native
client applications.
Delegation Permissions: Your application needs to access the web API as the signed-in user, but with access limited by the selected
permission. This type of permission can be granted by a user unless
the permission is configured as requiring administrator consent.
Based on this if your application requires user impersonation, then you would need to use Delegation permissions.
Related
I have created an API that is protected by OAuth using an app registration in Azure.
My app registration does not require assignment, but it exposes a number of roles that the underlying API verifies. To my understanding, this accomplishes almost the same thing as requiring approval.
So far I've only had user/group roles but now I've added an application role intended for integrators, and I want other application owners to be able to request permission to my API. I, as the API owner, would like to review these and either reject or consent to the request. E.g. I don't want everyone to be able to access my API within the tenant without my knowledge, just like all users/groups don't have access with me assigning them to a role.
The Role-based access control for application developers documentation makes it very clear who manages access:
...an application developer defines roles rather than authorizing individual users or groups. An administrator can then assign roles to different users and groups to control who has access to content and functionality.
However, if you create a role with allowed member types set to application, things are not quite as clear and it seems to behave more like a scope, where I give up any access management. Also from my limited understanding, a scope is used when the API needs to request data from the user (e.g. wanting to read their username), whereas a role is used for the application developer to control access to what they are developing.
This is what it looks like when I request access to my API from another app:
This same page mentions the following information:
The "Admin consent required" column shows the default value for an organization. However, user consent can be customized per permission, user, or app. This column may not reflect the value in your organization, or in organizations where this app will be used.
As well as:
Applications are authorized to call APIs when they are granted permissions by users/admins as part of the consent process
However, from my reading, it sounds like this never gives me, as the API owner, any insight into who has access to the API I own. I want to control application access the same way I'd assign a group or user to a role in the enterprise application.
Can this be achieved when it's an application on the other end, not a user? If not, how would I allow applications to integrate in a controlled manner?
I want to explain the feature Azure ad provided to protect web api here.
As you know, we usually use a token in the request header to let the api check if the request had correct permission to visit the api. Such as if the request from an allowed user role, right? So to whole progress should be authentication and authorization. Users sign in first then try to generate an access token to visit an api. Azure AD has similar architecture.
If you had a web application(e.g. web mvc app) you can integrate Azure AD into it then you can allow users use their user1#xx.onmicrosoft.com account to sign in. If you had a web api project, you can also integrate Azure ad and add [Authorize] attribute above the controller so that the incoming request should contain a correct Bearer token which we call it access token.
For Azure AD, we usually have 2 options, verification scopes or app roles. That results from the different flows we used to generate the access token. For example, we use auth code flow to sign in users and generate access token containing scp claim which is granted delegated api permissions. And we use client credential flow to let an application to generate access token containg roles claim which representing it's granted application api permissions. In short, when we set [Authorize] + [RequiredScope(scopeRequiredByApi)] in the controller, it allows requests from a user(user sign in the app and call api), when we set [Authorize(Roles = "roleRequiredByApi")], it allows requests from the application(no user signed in and the app call api by itself).
Here scopeRequiredByApi and roleRequiredByApi is what you exposed and then added to App Registration > Permissions. Just like Integrator you marked in the screenshot, it can be recognized as roleRequiredByApi because its type is Application.
And I'm afraid the roles is not what you want but to be honest what I said is what AAD can do for you... And I think the document I mentioned above about verification scopes or app roles will be a good sample for you.
The App Registration > Permissions section has a great feature for reviewing and limiting the access provided for your app registration:
enter link description here
In addition you should always define the scope of your permissions and limit it to the least required for your app. eg. NEVER set scope at the subscription level! Always set it at the resource group or lower.
Also note that Microsoft now provides Defender for APIs and you can use Sentinel to monitor a lot of the activities related to your app registration. Always always enable logging wherever possible and configure some method of alerting/reporting so you can better understand the activities for your app.
I have a SPA React application which use MSAL for logging users in and acquiring tokens for querying MS Graph. Currently, when the user is created he/she can have two different roles, namely:
Administrator
Viewer
As is, every user is allowed to get the same scopes from AAD - Regardless of whether they are one or the other role.
This presents a problem - Because any of the users potentially have the same permissions when calling MS Graph, i.e. they could acquire the token themselves and request graph with full scopes.
The viewer role should only be able to have the [User.Read] scope, while the administrator should be able to alter every aspect of Azure AD.
Additionally, the administrator should be able to perform actions in MS graph that isn't supported by delegated permissions, i.e. creating new users.
The following makes me think that I may need to rethink the way that users are requesting resources from MS graph - which lead me to thinking that the on-behalf-of flow would be an interesting option.
As I imagine, the flow would work as follows (from when a user logs in, and requests to create a new user in my SPA)
User logs in with MSAL in my SPA
User gets the least privileged scope, i.e. [user.Read]
User creates a new user
SPA sends a request to my Web API with the users' token as bearer
Web API validates the user token with AAD
Web API validates that the user has a role of "Administrator"
Web API gets a token with ["User.ReadWrite.All", "Directory.ReadWrite.All"] scopes
Web API calls graph with the fetched application scopes on behalf of the user
Web API returns the data to my SPA
Since I'm fairly new to this world - I'm wondering if my way of thinking makes sense. In particular, I'm curious if it's really possible to request elevated permissions ["User.ReadWrite.All", "Directory.ReadWrite.All"] on behalf of a user with only the [user.Read] scope from my Web API.
Additionally, I'm of cause open for any suggestions for alternative ways to solve the above issue.
Scopes (delegated permissions) apply to an application, not a user.
Fundamentally, no matter what scopes the user gets in their token, they cannot do anything they were not already able to do.
Microsoft Graph API checks the scopes to check the application's permissions, and then checks the user's permissions to see if they are also able to do the operation.
Thus a user can never elevate their permissions through scopes.
If you have any of your own APIs, you should also handle authorization in a similar way.
If scopes are used, also check the user's permissions.
In case of application permissions (app roles with member type application), there isn't a user so your API would only check these permissions.
This is why you need to be extra careful with authorization if your back-end uses application permissions instead of on-behalf-of flow; since they don't include the user, it could allow them to elevate their privileges through your application.
I've created a sample web application calling a Web API and using oAuth code grant flow against Azure AD.Application is registered in Azure AD and I have given required permission as well through Azure portal. Everything seems working as expected.
There are two option for permission
Delegate Permission
Application Permission
Is it recommended to use mix kind of permission set (App + delegate) for your application?
If I give similar kind of permission to my API on both Delegate and Application,which permission set will take precedence? Will it depend on oAuth flow e.g. Code grant or Implicit ?
In my code how can I differentiate these permission sets while accessing the same resource.I want to call on user context only even same type of application permission is already there?
Application Permissions and Delegated Permissions are completely independent of one another.
Application Permissions apply when you follow the Client Credential Flow (also known as App Only Flow). When you follow this flow, AAD will try to grant permissions to the client application based on the Application Permissions it has predefined in the app registration. These permissions will appear in an App Only Token in the role claim.
In nearly every other flow, where a user is involved (On-Behalf-Of, Authorization Code Grant Flow, Implicit Grant Flow, etc...) AAD will try to grant permissions to the client based on the Delegated Permissions it has predefined. These permissions will appear in App+User tokens in the scp (scope) claim.
You can control the kinds of permissions your app is granted by adjusting the authentication method when getting an access token to a resource.
I'm trying to get information about Azure Active Directory groups using the Graph API, but I keep getting an "Authorization_RequestDenied" response.
This question is similar to Insufficient privileges error when trying to fetch signed in user's group membership using Azure AD Graph API, but that question's answer didn't work for me.
Here's what I've done:
Logged onto the Azure portal using my Microsoft account (e.g. example#hotmail.com)
Set up an Azure Active Directory instance for testing. The domain of the instance is something like examplehotmail247.onmicrosoft.com
Created a user (TestMember#examplehotmail247.onmicrosoft.com)
Created some groups, and made the user part of those groups
Created an ASP.NET application configured to authenticate to AAD using OpenID Connect.
Registered the application in AAD, created client secret, reply URL, etc.
Modified the manifest of the application in AAD so that group membership claims are returned.
The authentication part works fine. After the user logs on, I can see all the information I expect (name, ID, etc.), along with claims containing the IDs of all the groups the user belongs to.
So far, so good.
Now, I want to translate those group IDs to human-readable group names. For this, I'm using the Microsoft.Azure.ActiveDirectory.GraphClient NuGet package, which provides a GetObjectsByObjectIdsAsync method. This method seems to be a wrapper for the getObjectsByObjectIds REST method.
To try and get this working, I've done the following:
In the Azure portal, I've granted the "Sign in and read user profile" and "Read directory data" permissions to my application.
Logged in to my ASP.NET application at least once using my Microsoft account
What I see: When I log in to my ASP.NET application using my Microsoft account, everything works. However, when I log in using the AAD account I created (TestMember#examplehotmail247.onmicrosoft.com), it fails with the following error:
[DataServiceClientException: {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."},"requestId":"1234e0bb-3144-4494-a5fb-12a937147bcf","date":"2016-12-06T18:39:13"}}]
System.Data.Services.Client.BaseAsyncResult.EndExecute(Object source, String method, IAsyncResult asyncResult) +919
System.Data.Services.Client.QueryResult.EndExecuteQuery(Object source, String method, IAsyncResult asyncResult) +116
Trying the equivalent query using the REST api directly (i.e. taking ASP.NET out of the picture) gives the same result.
So what am I missing here?
Update: I also granted the application the following delegated permissions (to Windows Azure Active Directory): Sign in and read user profile, Read directory data, Access the directory as the signed-in user. However, it didn't make any difference.
Update #2: I even made the TestMember#examplehotmail247.onmicrosoft.com a Global Administrator for the AAD instance, and it still didn't help.
Update #3: Ok, so first, some clarification. After a user logs on, my ASP.NET app gets an authorization code from the OpenID Connect flow. Once I get the code, I'm exchanging it for an access token using AcquireTokenByAuthorizationCodeAsync. The access token is tied to the user, and so I want to rely on delegated permissions, not application permissions.
The problem was that although the proper delegated permissions were granted to my ASP.NET app in the Azure portal, the user never had an opportunity to consent to them.
I started over by creating a completely new app registration in azure for my ASP.NET app, and here's what I found: When a user logs on for the first time, they are asked for consent to whatever delegated permissions are required. However, if I change which delegated permissions are required after they've logged on for the first time, the user is not asked for consent (for the newly-required permissions) the next time he logs on.
This is definitely not what I expected, so I'm going to open a new question about this.
From below, what I infer is when the application is configured with Delegated Permissions it makes all requests on behalf of the signed-in user.
So, under Delegated Permissions, again we have "Access the directory as the signed-in user" option listed. What does this actually do?
Application Permissions: Your client application needs to access the
Web API directly as itself (no user context). This type of permission
requires administrator consent and is also not available for Native
client applications.
Delegated Permissions: Your client application needs to access the Web
API as the signed-in user, but with access limited by the selected
permission. This type of permission can be granted by a user unless
the permission is configured as requiring administrator consent.
So, under Delegated Permissions, we have "Access the directory as the
signed-in user" option listed. What does this actually do?
In very simple words, the application essentially impersonates you (or the logged in user) in case of delegated permissions.
To give you an example, let's say you created a web application in your Azure AD with delegated permissions to access Azure Service Management API. Now when you login into this application and try to access your Azure resources (storage accounts, VMs etc.), the application will only be able to do things you're granted permission to do in that Azure subscription. For example, if you're in Reader role in your Azure subscription (i.e. you can't create/update/delete resources). If you try to create a resource through your application you will get an error back because the application is impersonating you.
Delegated permissions require a user to login to Azure AD and present the resulting authentication token to your application. Your application can make calls by passing your client id, secret (if applicable) and the user's authentication token. Your application's effective permissions will be the lowest combination of the user and your application. For example, if your application has been granted read/write to a resource but the user only has read, your effective permissions are read. The same is true if the user has read/write but the application only has read.
Application permissions do not require a user to login. Just your client id and secret are enough. If you do not have application permissions and attempt to access the api without also presenting an authenticated user's token you will receive 401 errors.