How to use Azure Active Directory claims to set User group
I'm using Azure Active Directory to provide authentication to the Backoffice on my website running Umbraco version 11.0.
This is working nicely and I can log in but I want to improve the experience by using app roles within Azure to manage the user's group within Umbraco.
My Azure setup
I've created an App Registration within Azure with the following configuration:
Enabled ID tokens (used for implicit and hybrid flows)
Supported account types: Accounts in this organizational directory only (Umble only - Single tenant)
Added App Roles
Administrator
Editor
In Enterprise Applications, I've also added the App Roles above to my users:
My code
Login Provider
namespace Example.Api.Features.Authentication.Extensions;
public static class UmbracoBuilderExtensions
{
public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder)
{
builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();
builder.AddBackOfficeExternalLogins(logins =>
{
const string schema = MicrosoftAccountDefaults.AuthenticationScheme;
logins.AddBackOfficeLogin(
backOfficeAuthenticationBuilder =>
{
backOfficeAuthenticationBuilder.AddMicrosoftAccount(
// the scheme must be set with this method to work for the back office
backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName) ?? string.Empty,
options =>
{
//By default this is '/signin-microsoft' but it needs to be changed to this
options.CallbackPath = "/umbraco-signin-microsoft/";
//Obtained from the AZURE AD B2C WEB APP
options.ClientId = "CLIENT_ID";
//Obtained from the AZURE AD B2C WEB APP
options.ClientSecret = "CLIENT_SECRET";
options.TokenEndpoint = $"https://login.microsoftonline.com/TENANT/oauth2/v2.0/token";
options.AuthorizationEndpoint = $"https://login.microsoftonline.com/TENANT/oauth2/v2.0/authorize";
});
});
});
return builder;
}
}
Auto-linking accounts
namespace Example.Api.Features.Configuration;
public class OpenIdConnectBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions<BackOfficeExternalLoginProviderOptions>
{
public const string SchemeName = "OpenIdConnect";
public void Configure(string name, BackOfficeExternalLoginProviderOptions options)
{
if (name != "Umbraco." + SchemeName)
{
return;
}
Configure(options);
}
public void Configure(BackOfficeExternalLoginProviderOptions options)
{
options.AutoLinkOptions = new ExternalSignInAutoLinkOptions(
// must be true for auto-linking to be enabled
autoLinkExternalAccount: true,
// Optionally specify default user group, else
// assign in the OnAutoLinking callback
// (default is editor)
defaultUserGroups: new[] { Constants.Security.EditorGroupAlias },
// Optionally you can disable the ability to link/unlink
// manually from within the back office. Set this to false
// if you don't want the user to unlink from this external
// provider.
allowManualLinking: false
)
{
// Optional callback
OnAutoLinking = (autoLinkUser, loginInfo) =>
{
// You can customize the user before it's linked.
// i.e. Modify the user's groups based on the Claims returned
// in the externalLogin info
autoLinkUser.IsApproved = true;
},
OnExternalLogin = (user, loginInfo) =>
{
// You can customize the user before it's saved whenever they have
// logged in with the external provider.
// i.e. Sync the user's name based on the Claims returned
// in the externalLogin info
return true; //returns a boolean indicating if sign in should continue or not.
}
};
// Optionally you can disable the ability for users
// to login with a username/password. If this is set
// to true, it will disable username/password login
// even if there are other external login providers installed.
options.DenyLocalLogin = true;
// Optionally choose to automatically redirect to the
// external login provider so the user doesn't have
// to click the login button. This is
options.AutoRedirectLoginToExternalProvider = true;
}
}
In this file, I'd ideally do as the comment says and i.e. Modify the user's groups based on the Claims returned in the externalLogin info.
Current state of play is that I can login just fine but if I debug externalInfo, there's nothing in there about the users having either the Administrator or Editor App Role as configured above.
My gut feeling is that I'm missing something with the Azure Active Directory setup but I've tried a few different configurations and can't seem to get the App Roles to come back.
To solve this, I ended up swapping out the AddMicrosoftAccountAuthenticationBuilder in favour of AddOpenIdConnect. This appears to respect the claims in the tokens.
This is the code I am now using in the ConfigureAuthentication method.
public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder)
{
// Register OpenIdConnectBackOfficeExternalLoginProviderOptions here rather than require it in startup
builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>();
builder.AddBackOfficeExternalLogins(logins =>
{
logins.AddBackOfficeLogin(
backOfficeAuthenticationBuilder =>
{
backOfficeAuthenticationBuilder.AddOpenIdConnect(
// The scheme must be set with this method to work for the back office
backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName),
options =>
{
options.CallbackPath = "/umbraco-signin-microsoft/";
// use cookies
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// pass configured options along
options.Authority = "https://login.microsoftonline.com/{tenantId}/v2.0";
options.ClientId = "{clientId}";
options.ClientSecret = "{clientSecret}";
// Use the authorization code flow
options.ResponseType = OpenIdConnectResponseType.Code;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
// map claims
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
options.RequireHttpsMetadata = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.UsePkce = true;
options.Scope.Add("email");
});
});
});
return builder;
}
Thanks a lot for sharing your workaround. Can you perhaps show how it looks your OpenIdConnectBackOfficeExternalLoginProviderOptions class now? I would really love to see how you update the user groups in there.
I know it's a old post. But maybe someone can use it :=)
OnExternalLogin = (user, loginInfo) =>
{
// You can customize the user before it's saved whenever they have
// logged in with the external provider.
// i.e. Sync the user's name based on the Claims returned
// in the externalLogin info
var name = loginInfo.Principal.Claims.Where(c => c.Type == "name").FirstOrDefault();
var roles = loginInfo.Principal.Claims.Where(c => c.Type == ClaimTypes.Role).ToList();
if (roles.Count > 0)
{
user.Roles.Clear();
foreach (var role in roles)
{
var umbracoRole = GetUmbracoRoleWithMostPrivileges(role.Value);
user.AddRole(umbracoRole);
}
}
user.Name = name.Value;
return true; //returns a boolean indicating if sign in should continue or not.
}
Hello, I am trying to implement this solution but I get asked about authorization from the Administrator. Even if I did set up users inside Azure Group.
How can I solve it? Is there a workaround to avoid it or should I request Administrator to disable Approval Required screen?
How to use Azure Active Directory claims to set User group
I'm using Azure Active Directory to provide authentication to the Backoffice on my website running Umbraco version 11.0.
This is working nicely and I can log in but I want to improve the experience by using app roles within Azure to manage the user's group within Umbraco.
My Azure setup
I've created an App Registration within Azure with the following configuration:
Access tokens (used for implicit flows)
ID tokens (used for implicit and hybrid flows)
Accounts in this organizational directory only (Umble only - Single tenant)
In Enterprise Applications, I've also added the App Roles above to my users:
My code
Login Provider
Auto-linking accounts
In this file, I'd ideally do as the comment says and
i.e. Modify the user's groups based on the Claims returned in the externalLogin info
.Also registered in my Startup file
Current state of play is that I can login just fine but if I debug
externalInfo
, there's nothing in there about the users having either theAdministrator
orEditor
App Role as configured above.My gut feeling is that I'm missing something with the Azure Active Directory setup but I've tried a few different configurations and can't seem to get the App Roles to come back.
Thanks,
Ben
To solve this, I ended up swapping out the
AddMicrosoftAccount
AuthenticationBuilder
in favour ofAddOpenIdConnect
. This appears to respect the claims in the tokens.This is the code I am now using in the
ConfigureAuthentication
method.Hi Ben,
Thanks a lot for sharing your workaround. Can you perhaps show how it looks your OpenIdConnectBackOfficeExternalLoginProviderOptions class now? I would really love to see how you update the user groups in there.
Thanks.
I would also love to see the code you've used to set the user groups based on their roles in the Active Directory B2C tenancy.
I cannot find any examples online, in the Umbraco docs, or Skrift articles / blogs that actually show the code for this...
I do it like this :)
I know it's a old post. But maybe someone can use it :=)
Hello, I am trying to implement this solution but I get asked about authorization from the Administrator. Even if I did set up users inside Azure Group. How can I solve it? Is there a workaround to avoid it or should I request Administrator to disable Approval Required screen?
is working on a reply...