Microsoft Graph API - new delegated permission removing application permissions - azure-active-directory

I'm using the v1 Azure AD auth URLs (/common/oauth2/authorize) for a multi-tenant app that requires admin_consent.
I've attempted to add a new scope Directory.AccessAsUser.All. It is the first 'delegated' permission I'm requesting when all my other scopes are 'application' level permissions.
When I added that new delegated scope and prompted the admin to re-consent, the other scopes disappeared from the returned AccessToken and the responses scope parameter. Only Directory.AccessAsUser.All is present in the access_token scp field.
Is there any reason this behavior would occur? I'm positive that we are promoting for admin_consent and that an admin is the one consenting.

The scopes specified in the scp will depend on which OAUTH flow you used to obtain the token. You cannot have a single access_token with both Delegated and Application scopes.
Application scopes are applied when using the Client Credentials flow (client_credentials).
Delegated scopes are applied when using either Authorization Code or Implicit flows (authorization_code or implicit).
Update: I've written a more in-depth post about this topic that might help folks facing similar issues: Application vs Delegated Scopes.

Related

What's the difference between User.Read and OpenID+Profile+Email scopes

Does User.Read "contain" the permissions email openid and profile? I've found that apps that are requesting the 3x scopes, can instead accept just the User.Read permission and still function equivalently
At work I'll get requests from the business to help them setup SSO using OIDC, and I'm not actually sure what permissions I should be giving them. Seems like either option works but I'd like to better understand what's happening
See my observations below:
I've created a basic Function App, and configured it to use OpenID Connect Image
My App Registration already has the User.Read permission with admin consent, so when I log into my Function, there's no issue.
Image
However, after removing the User.Read permission and logging in, I now get a permissions request prompt Image
And after consenting to the permissions, I can now see that email openid and profile permissions were added Image
Even more interesting, the permissions in the request prompt correlate to openid and offline_access, but offline_access wasn't added, while email and profile weren't in the request
I did find a similar question, but the accepted answer doesn't seem to align with what I see here
Generally I would favour the OAuth standard design where fields like these are Personally Identifiable Information (PII). So each app should only use the smallest scope it needs, as an information disclosure best practice. See also this Curity article.
Name
Email
Phone
Address
The Graph API can also be used with standard scopes, as in step 11 of this blog post of mine, where I wanted to get hold of user info in an API. So if this works for you I would prefer it. Personally I also prefer standard scopes so that my application code is portable.
Microsoft's design is based on each API requiring a different access token, the resource indicators spec. It is interesting, though perhaps not always intuitive. I am no expert on Azure AD though, and there may be some intended usage I do not understand.
User.Read is a scope intended to be used when requesting an access token for the Microsoft Graph API. It grants privileges to read the profile of the signed-in user only. A separate call to the Microsoft Graph API is required to retrieve the profile.
openid, email, profile and offline_access are OpenID Connect scopes:
openid is used to request an id token.
offline_access is used to request a refresh token which can later be used to get a new access token.
email to request an email claim.
profile to request several user claims (Eg.preferred_username).
Both email and profile can be used to augment information available in the UserInfo endpoint, however, it is recommended to use the id token which is already a superset of the information available at the aforementioned endpoint.

What is the correct use of scopes and app roles in an Azure AD web api with user and daemon clients?

I have a web api to access "resources". These are not user specific resources.
There is a "reader" app role.
User1 is added to "reader" role
App1 has been granted permission to the "reader" role
[HttpGet]
[Authorize(Roles = "Reader")]
[RequiredScope("Asset.Read")]
public async Task<IActionResult> GetResource(Guid resourceId)
When user1 accesses the route, (with a token with the scope) it works.
When app1 tries to access the route it gets a 403 forbidden, even though it had ".default" which I thought would give it access to all scopes?
Question 1: Why can't app1 access the route?
Question 2: Why do I even need a scope? It seems like there is a lot of conflicting documentation on why to setup scopes.
Question 1: Why can't app1 access the route?
In addition to what RahulKumarShaw-MT has answered, this likely is because for the OauthV2 Client Credentials flow for AzureAD, the JWT token issued with the /.default scope in the request does not bear an scp parameter for delegated permissions. This is likely what the "Asset.Read" scope is. For your scenario, you'll need to verify the scope parameter exists in the JWT in the case of clients that access data on behalf of the user e.g. Single Page Apps that do not use the Client Credentials flow, but skip the scope verification for Daemon Apps or confidential clients that use the Client Credentials Flow. This question highlights a similar issue to the one you're having.
Question 2: Why do I even need a scope? It seems like there is a lot
of conflicting documentation on why to setup scopes.
You only need the custom-defined scope if your App is performing actions on behalf of the "signed in" user. Such as reading user data. If however, the App is not doing this and is instead a Daemon App or service in a non-public environment that can hold a client secret, then you should be able to assign an App Role and use the client credentials flow without verifying the app scope. App roles assigned to Daemon Apps will require admin consent.

Azure AD: silently get token with particular scope, but get token without this scope

I set up Web Api Application in Azure AD and define some scopes here, also set up SPA Application and give permission to created scopes.
When I login I requested that definitely this api scope included and I need to give permission to it. But when I request token silently with this scope I couldn't find that it has been incorporated in token.
Here request to get token with app scope
Here what token I get (without my custom scope):
Could you help me, why it's happening?
User.Read is a permission of Microsoft Graph. It recognizes the resource you want to access as Microsoft Graph.
Please remove it when you refresh your access token. Just put api://{client-id}/access_as_user openid profile offline_access as the scope.

Adding custom claims into AAD token

Is it possible, while acquiring an access_token (Client Credentials grant), to instruct AAD to inject certain custom claims with certain values into the access_token being issued?
I need it to avoid sending extra context information to my service through such a "disconnected" means as HTTP Header for instance. Instead I want the token signed by AAD and containing everything AAD stamps into it by default plus some small pieces of information controlled by the application acquiring the token. All this will help my service to apply proper authorization once this token is received by the service.
I looked at the above, and I am clear that you are not looking for claims augmentation as it was described in the blog.
As I understood, you are looking for the right way to authorized your application using AAD tokens.
If my understanding is correct here is my answer.
It took me quite sometime to remember how I did it before and the caveat was missing the graph permissions for:
Directory.AccessAsUser.All
Directory.Read.All
Directory.ReadWrite.All
Now let me type down the steps one by one, but care less to the order of these steps may not be correct, just do the steps in any order you want.
Step 1: In AD, in the App registration
Register your Web Application,
Copy the Client_ID
Step 2: Go to Expose an API
Add a scope or more (This is what you are going to see as a claim and role in the token)
Add the client Client_ID
Note: this is basically for 2 applications one calling another, but in this example and your case, you have one web application that needs to authorize on itself.
Next: In the API permissions
THIS IS A MUST grant admin consent delegated permissions for MicrosoftGraph
Directory.AccessAsUser.All
Directory.Read.All
Directory.ReadWrite.All
Additionally: Give permission to the scope that you added.
Then: In the App roles:
Add the Application roles
Then: In the Enterprise Applications:
Assign that role to the users or groups that you want to access this.
Finally: In the application configuration file
Update the Client id
You are done.
I hope that was what you were looking for.

OAuth with Azure Active Directory: Azure AD returns incorrect value for the State parameter after denying admin-consent scopes

During OAuth interaction with Azure AD, it appears that Azure returns incorrect value for the State parameter after users deny grant for admin-consent scopes.
When constructing the URL for requesting authorization code from Azure AD via the Azure AD v2.0 endpoint https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize, let say I specify the State parameter as a+b.
Then url encoding the State parameter value to a%2Bb and then put in the URL for requesting authorization code from Azure AD
If the request specifies scopes that require administrator consent and have not be granted in the past, Azure returns the following page as expected:
I was trying to verify my application logic for handling errors returning from Azure. So I denied this consent by clicking the Return to the application without granting consent link. After that, Azure expectedly returned an error response to my app's redirect URI. Azure populated the data in the HTTP body as follows:
Azure populated the State parameter value as a%252bb. This is not correct. The expected value should be a%2Bb - i.e. same as the value specified earlier when calling the Azure authorization code request endpoint as described earlier. It looks like Azure somehow performed a double URL encoding - in other words, encoding an already url-encoded State parameter, changing a%2Bb to a%252bb. (% was encoded to %25. In addition it is strange that B somehow became b)
It appears that Azure has this issue in the code path for handling users clicking the Return to the application without granting consent link for denying admin-consent scopes. For the other scenario of users denying user-consent scopes, it appears that Azure does NOT have this issue. Azure returns a proper value for the State parameter as illustrated as follows:
I tried again today. Looks like Microsoft has just removed the Return to the application without granting consent link. So the issue mentioned in this post earlier no longer exists.

Resources