Azure AD + Graph API: How to reconsent after new permissions? - azure

I have an application registration in Azure AD which has some Graph API delegated permissions set for it.
The application is simply a page in SharePoint that is making the Graph calls, authenticating with the ADAL.js library.
I now want to make an additional Graph call on the page to a new Graph API endpoint so I need to assign the application an additional permission. I set this permission in Azure AD and save. However, the user accessing the SharePoint page is never asked to reconsent to the new permissions, therefore the new Graph call fails with a 401 Unauthorised message.
I have tried this with a number of different endpoints and permissions, and I am sure I am setting the correct permissions in the application.
How can I have the consent dialog appear for users automatically when the application permissions change?
Admin consent is not an option.

I remember having a discussion about this with a member of Azure AD team some time back and this is what he had suggested at that time (though I never tried it so it may not work).
Essentially what he suggested is that when you get Unauthorized (401) error, you redirect the user to Azure AD login again i.e. follow OAuth authorization flow again but include prompt=consent in the sign in URI. This will present the user a consent page with latest permissions. Once the user consents to the latest permission, you can redirect the user back to your application. You may find this link helpful for understanding different values for propmpt parameter: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code.
Again, I have not tried this personally so it may not work. If it doesn't, please let me know and I will remove my answer.

Related

How do I add administrator accounts for granting static permissions to my Azure AD App?

I have set up a Azure Active Directory App so that I can access the Microsoft Graph API with MSAL. However, I want to perform API calls without a user (https://learn.microsoft.com/en-us/graph/auth-v2-service) and as such I have added a few permissions that require "Admin consent" to my app. However, I cannot find a way to grant my app these permissions.
I've tried looking around the Azure portal for a way to grant these permissions but without success. I have also tried using the https://login.microsoftonline.com/{tenant}/adminconsent&... link to grant permissions, but unsucessfully so.
The response I received was
AADSTS500201: We are unable to issue tokens from this API version for
a Microsoft account. Please contact the application vendor as they
need to use version 2.0 of the protocol to support this.
I do not have an Azure subscription (not even the free one), but seeing as I was able to add apps to Azure AD as well as get access tokens and then make API calls on behalf of the authorized users I assumed I might not need a subscription.
I just made another app and now I have the grant consent button when I open the API Permissions view.

Identical Azure apps do not work in different tenants

I use Azure apps to sign users in to a web app and a desktop app. I also query for user information via Microsoft Graphs /user/ endpoint.
So we have to apps registered in Azure; one is a web app / api with permissions to sign users in and read all user profiles from graph. The other is a native app with permissions to the first app, and permissions to sign users in.
In one tenant, this works fine. However in the other tenant the web api har permissions to sign users in, but Graph declines access to the /users/ endpoint due to insufficient privileges. The error is: Authorization_RequestDenied, Insufficient privileges to complete the operation.
However the exact same privileges work fine in another tenant. In the faulty tenant we get a token from graph but when we use the token on the user endpoint it throws the insufficient priv. error.
Signing in users via the desktop app (we use owin) works in one tenant but in the faulty one it sais that app tenant.onmicrosoft.com/guid does not exist in tenant.onmicrosoft.com
The app uri is correct in the settings and the app has the same privileges in both tenants.
We tried recreating the apps since this has solved similiar issues when developing things like this before. This time it doesnt seem to work however. Now I'm at my wits end here. Could there be some other issue blocking here?
The faulty tenant is part of a multi-tenant. However we only poll for users in one tenant as of now.
The apps have also been given consent by an admin via the azure portal. What am I missing here? How should i proceed with trying to fix this error?
Edit: I added a new directory in my tenant and it does not work in this new directory. Same error as with our clients tenant.
Working token for directory A:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUQkVOV21GUUgtZjRGS0VjYlIwU3Y1NndrdzhvSjhjbDIwX3JtZEJBc2h6eDhKT2VNZjFEbVFjNm1GUUdxZ2VSRFJZMTEzNXE3ZXJkTjlHTFZ6T3NycnlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIiwia2lkIjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NTYzNTY2OC03OGNlLTQzNDMtODMzYy0xOWM5ODkzNTRkZWYvIiwiaWF0IjoxNTM5NjExMjk2LCJuYmYiOjE1Mzk2MTEyOTYsImV4cCI6MTUzOTYxNTE5NiwiYWlvIjoiNDJSZ1lNaWExaldMdTJqUmkvWjlQenU4bHZkUEJRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJLRVlPMzY1IiwiYXBwaWQiOiI1MmQwMTdmZi1lY2ZjLTQ2NjgtYjZkZi0zZDNlZGYwZDFjNjIiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83NTYzNTY2OC03OGNlLTQzNDMtODMzYy0xOWM5ODkzNTRkZWYvIiwib2lkIjoiMjM0ZDhmZTctNmYwZC00NmEwLWI1YmYtNzg1MWY0ZmFmNmMyIiwic3ViIjoiMjM0ZDhmZTctNmYwZC00NmEwLWI1YmYtNzg1MWY0ZmFmNmMyIiwidGlkIjoiNzU2MzU2NjgtNzhjZS00MzQzLTgzM2MtMTljOTg5MzU0ZGVmIiwidXRpIjoiUDNvc0hHdHQyMFdRTXhkLVFxcWNBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNDQ3MDYyNTMyfQ.prmIaq8PzXfeovQPeIYS20xvZqpjPH-DvZNwQ3v08KOhTnfFaiCkxtw2wh1B37QQDbOveYqCWRi2CE6Uwpb6zg3-tFh1ma852HDqnJHYCKPajxeW9oIewAnCagB5FzOLQRT_EbX-lEREQVcPUHSZpRNmAWEM2MOZjDnkWun_aqohf_1op7Cy40Ol_PkRzoEgmA7pbXeI28IMPW3S4a5M_hBo_MZzRbVdxuG8YQKkVMWX0wAhpLHAYbdF1Rv5sITEpBP-KHdgJkTswLs3xvIRLyXxrXobG1aVQihr7LHFoCIU0NAcCUQLS2xkePuYGRB09k7hFQsbSNxoJSywBZWk7w
non working token for directory B:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDNXVuYTBFVUZnVElGOEVsYXh0V2pUUS1NMnBUdmVjYTgzUXFuVmlBWWpJX0dLNHZrMTBMYVF2dGF5SGQ0WmZDVlRySm0wSmtOVDU2UlJSU0NuUlFPU0k0aVNHdXZZZ1cxelpaTE9KTkJTVHlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIiwia2lkIjoiaTZsR2szRlp6eFJjVWIyQzNuRVE3c3lISmxZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC84MTFjNjA2OS1kZDE4LTRmN2UtOTlhMy1lNjA2YzMyYjhhMjAvIiwiaWF0IjoxNTM5NjExMjI1LCJuYmYiOjE1Mzk2MTEyMjUsImV4cCI6MTUzOTYxNTEyNSwiYWlvIjoiNDJSZ1lPZzlraUZYR3BxNCtVMko1NHAvL2N2M0FRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJGZXRjaGluZ1VzZXJzQXBwIiwiYXBwaWQiOiJiNDAyZjI5Ni05OTAxLTRjNmMtYjA2MC1hNGI1M2VjNmMzMDQiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC84MTFjNjA2OS1kZDE4LTRmN2UtOTlhMy1lNjA2YzMyYjhhMjAvIiwib2lkIjoiYzIyZWJmNmEtZDNkYS00ZGRjLWIzZTYtOWFhY2VmZWY3MmE4Iiwic3ViIjoiYzIyZWJmNmEtZDNkYS00ZGRjLWIzZTYtOWFhY2VmZWY3MmE4IiwidGlkIjoiODExYzYwNjktZGQxOC00ZjdlLTk5YTMtZTYwNmMzMmI4YTIwIiwidXRpIjoiNk4xRnBkRVZEMGFvRnM0UndVRGZBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTM5MTU0MTkxfQ.l_7qgXkco5FWR7pbX5rQzAtvnrb1e6xOr5byrvkYDcyNa85KmCu5b6ArfjxTmeDR82XTmYw51n2YAbWl2q8R58dqELOguddwnKkBBCiMwKsD_UvG2oX_M9ZMy-Lc8lERduolyST7D0BZSoYCNe9f0j85AXIOgXr_yMA5MrVz7qSVFKZ1if2BR9YvvMCphW2uQCrebEJAnchyxHiCb5refnhm2sfsDBRJqd5NWwK0-a956a6dC2zg59JbW55-3wezQOfXKYzC5ybzO7l1hV41EnJ4atBW6EvR2er7WyCAFb1Y1hSB_wgZSo7pC4LnQRRm9KXq-x2aSRKiUSg265K0RQ
You need to receive Admin Consent for an administrator of the tenant. I'm assuming that because this happens when hitting /users, you've requested either User.Read.All or User.ReadWrite.All. Both of these require Admin Consent before a normal user can authenticate and provide User Consent.
I wrote an article a while back that you might find this helpful here: User vs Admin Consent. The examples target the v2 Endpoint while it sounds like you're using v1. That said, the same consent models and workflow apply to both v1 and v2.

Authorization_RequestDenied when trying to get groups from Azure Active Directory using Graph API

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.

B2B with Microsoft Graph

As you probably know, I am creating a multi-tenant azure application, which is using the B2B functionallity.
I am testing the B2B functionality and after some research I got a working sample.
Small summary: User authenticates against common authority, first token is acquired via common authority with the authorization code and from then, everytime I need a service client, I try to obtain those tokens from the 'current tenants' authority.
When I request 'Me', it only works against the home tenant. When I request me with a trusted tenant, I got an error that my user identifier does not exist in the directory. Probably because user does not actually exist in the trusted tenant.
When I request Users, it works fine. I can get both, home tenant users and trusted tenant users.
Is this normal behaviour?
Is this something I need to handle programmatically or would this been solved by using the AD graph?
(So when I know I need user info, just query the home tenant?)
Or is this a bug?
Any thoughts on this would be greatly appreciated!
Guests added to a directory via the B2B Collaboration feature will not work correctly on multi-tenant apps or the Microsoft Graph if you're using the common endpoint.
The common endpoint will always authenticate the user against his/her home tenant, not against any tenant where (s)he is a guest.
In order to successfully query /me for a guest, you'll need to have them sign-in through the tenant specific endpoint for the tenant where they're a guest.
See my answer to this other post for a more in-depth explanation / context:
Can users from an unmanaged Azure AD directory, sign into an Azure AD multi-tenant application which resides in a different directory?
I have noticed that when you want to switch between tenants, you need to re-authorize against the current tenant.
I got it working this way:
1. First sign-in needs to be done against the common endpoint.
2. Every time I need a token for certain resource, I try to get the token silently.
=> This can throw 2 different AdalSilentTokenAcquisitionException
Nothing found in cache, also no refresh token found
=> In this case, I redirect the user to the login page again.
When you switch between tenants, and it is the first time you want to login using a tenant where you've been trusted, you can get a error like: User or admin should be given consent for this application. Although the admin from his home tenant has added the application in the directory for the home tenant. Anyone who knows why this consent is needed? So tenant A and tenant B admins have both been given consent. Why does a trusted user from B in A still needs to consent someway?
I was able to trigger the consent flow by redirecting the user to the authorization request URL.
So when I got an AdalSilentTokenAcquisitionException, and the error code is "failed_to_acquire_token_silently" then I had to redirect the user to the URL generated by the authContext (authenticationContext.GetAuthorizationRequestUrlAsync) when the cache had been cleared, no refresh token will be found, then redirect the user to resign.

Azure Active Directory Login: Web App Permissions, User Consent not triggered

I have currently set up a AAD instance and I am authenticating my users against it via my web app, and it’s working great.
When I added and configured the application on AAD, I added the required Application and Delegated Permissions to access the Office365 Calendar API. However, the only thing that is missing is that during the login flow users aren’t being prompted to grant consent for the permissions, as it should happen from what I’ve read in your docs: https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx#BKMK_Consent
I’m not sure what I’m missing. Apparently, from the docs,
After the user has signed in, Azure AD will determine if the user
needs to be shown a consent page. This determination is based on
whether the user (or their organization’s administrator) has already
granted the application consent. If consent has not already been
granted, Azure AD will prompt the user for consent and will display
the required permissions it needs to function. The set of permissions
that is displayed in the consent dialog are the same as what was
selected in the Permissions to other applications control in the Azure
Management Portal.
So maybe somehow I have already probably implicitly granted admin consent for those permissions, but I don’t know how that happened.
I've attached the permissions I configured on the AAD App.
Any help would be appreciated.
If an admin creates an application in their tenant using the AUX portal (manage.windowsazure.com), and requests permissions to other applications, then users in that same tenant are pre-consented for that application. Note this behavior is NOT true for our other App Registration Portals (portal.azure.com or identity.microsoft.com)
I believe this is why you are not seeing the consent dialogue when user's in your tenant are signing into your application. If you would like to push the consent dialogue experience, there are a few different things you can do:
You can use query strings to prompt "consent" or "admin_consent" during login. Check here: https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx
You can delete the service principal for your application from your tenant using AAD PowerShell. You can learn how to do that here: https://msdn.microsoft.com/en-us/library/azure/dn194113.aspx
You can have a user from another tenant try to login to your multi-tenant application.
You can create your application under a non-admin account.
I hope this helps!
Shawn Tabrizi
Try this:
What is the Resource parameter in Windows Azure AD tenant application oAuth 2.0 specification
Changing the resource parameter to https://graph.windows.net did the trick for me.
Furthermore, Microsoft support suggests disabling all permissions except "Enable sign-on and read users' profiles", apparently to avoid permission related problems. I understand that this is not a solution in your case, but at least it gives you a test case.

Resources