I'm trying to have integration with AAD for the MVC web app made with IdentityServer4. I wanted to have a code authentication flow [https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow]. After my changes in existing code (current code is show later in the post), all seemed to work properly. However, after some testing I found out that when I'm trying to sign in with an account that does not have any administrator role assigned to it, the popup below is shown. Popup shown for users without admin role
And when I'm trying to sign in to the app with account that has administrator role this popup is shown Popup shown for users with admin role
It seems to be proper behavior to me, because one of the permissions requires the admin consent.
But the problem start when I consent the permissions on behalf of my organization (sing in as user with admin Global admin role). My expected behavior is that after granting consent by one of the admins, regular users can access the app.
The actual result is that the popup number 1 is still presented to users and they can't enter my application.
What is going in my code when user signed in successfully?
Basically, when user sign in with AAD to my app for the very first time, I want to add him to my users table in the DB. If it's not the first time he sign in, I want to update some info based on the profile and the group user is assigned to. To do so I need to read the basic user information and groups names using Microsoft Graph API.
The permissions (type=delegated) I configured for the app:
- GroupMember.Read.All
- User.Read
GroupMember.Read.All requires admin consent. What I found out is that I need this 'GroupMember.Read.All' to retrieve groups with properties such as DisplayName filled. And it seems this permission is causing the problem with signing in. (only with User.Read signing in works fine, but obviously I don't have access to groups names etc, there are only groups ids)
The code I use for getting signed in user group info:
var accessToken = authResult.Properties.GetTokenValue("access_token");
GraphServiceClient graphClient = GetClient(accessToken);
var groupsList = (await graphClient.Me.MemberOf.Request().GetAsync()).ToList();
As you can see, the access token is retrieved from properties of 'AuthenticateResult'.
Logic for getting this access_token to use graph resource is here below in Startup.cs file. Having authentication code returned I get access_token for Microsoft Graph and then I pass it to authentication result that I can use further in my services code like show above (getting groups the user is member of).
if (aadSettings.IsValid)
{
services.AddAuthentication()
.AddOpenIdConnect("aad", "Active Directory", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.Authority = aadSettings.ADAuthority;
options.ClientId = aadSettings.ADClientId;
options.ClientSecret = aadSettings.ApplicationSecret;
options.CallbackPath = aadSettings.CallbackPath;
options.SignedOutCallbackPath = aadSettings.SignedOutCallbackPath;
options.RemoteSignOutPath = aadSettings.RemoteSignOutPath;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
options.Prompt = "consent";
options.Scope.Add("https://graph.microsoft.com/User.Read");
options.Scope.Add("https://graph.microsoft.com/GroupMember.Read.All");
options.ResponseType = "code id_token";
options.Resource = "https://graph.microsoft.com/";
options.SaveTokens = true;
options.Events.OnAuthorizationCodeReceived = async contex => {
var authCode = contex.ProtocolMessage.Code;
var credential = new ClientCredential(aadSettings.ADClientId, aadSettings.ApplicationSecret);
var currentUri = UriHelper.BuildAbsolute(contex.Request.Scheme, contex.Request.Host, contex.Request.PathBase, contex.Request.Path);
var authContext = new AuthenticationContext(aadSettings.ADAuthority);
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(authCode, new Uri(currentUri), credential, options.Resource);
contex.HandleCodeRedemption(result.AccessToken, result.IdToken);
};
});
So the question is: How can I solve the issue with signing in for users without admin roles? and how can i get groups the user is assigned to? Am I missing some configuration in AAD? Or maybe I'm using wrong permissions?