Implementing a multi-tenant OIDC Azure AD external login for IdentityServer4

This article shows how to setup a multi-tenant Azure AD external login for IdentityServer4 which uses ASP.NET Core Identity.

Code: IdentityServer4 app with Identity

Setting up the Azure AD Application registration for multiple tenants

An Azure AD Application registration needs to be setup for the Active Directory tenant.

Login to the Azure portal and switch the directory to the Azure Active Directory tenant. Then click the “Azure Active Directory/App Registrations” menus and then the “New application registration” button.

Create a new App registration. The sign-on URL should be set to the “App_URL”/signin-oidc

In the Settings, Properties, change the application to a multi-tenanted one.

Check that all the reply URLs are correct. These must match the calling IdentityServer4 application URL with “/sign-oidc”

Here’s an example:

https://localhost:44318/signin-oidc

Adding the Azure AD login to IdentityServer4

In the IdentityServer4 application, add an OIDC authentication using the AddOpenIdConnect extension method. The Authority is set to the common login from Azure AD. The token validation is turned off, because mutliple tenants can be returned. The CallbackPath path should match the application registration configuration.

services.AddAuthentication()
 .AddOpenIdConnect("aad", "Login with Azure AD", options =>
 {
	 options.Authority = $"https://login.microsoftonline.com/common";
	 options.TokenValidationParameters = 
              new TokenValidationParameters { ValidateIssuer = false };
	 options.ClientId = "99eb0b9d-ca40-476e-b5ac-6f4c32bfb530";
	 options.CallbackPath = "/signin-oidc";
 });

IdentityServer4 is configured to use Identity using the IdentityServer4.AspNetIdentity NuGet package.

services.AddIdentity<ApplicationUser, IdentityRole>()
	.AddEntityFrameworkStores<ApplicationDbContext>()
	.AddDefaultTokenProviders();

services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();
services.AddTransient<IEmailSender, EmailSender>();

services.AddIdentityServer()
	.AddSigningCredential(cert)
	.AddInMemoryIdentityResources(Config.GetIdentityResources())
	.AddInMemoryApiResources(Config.GetApiResources())
	.AddInMemoryClients(Config.GetClients(stsConfig))
	.AddAspNetIdentity<ApplicationUser>()
	.AddProfileService<IdentityWithAdditionalClaimsProfileService>();

Add the razor code to the login page which displays the OIDC login button.

@if (Model.ExternalProviders.Any())
{
    <div class="row">
        <div class="panel-body">
            <ul class="list-inline">
                @foreach (var provider in Model.ExternalProviders)
                {
                    <li>
                        <a class="btn btn-default"
                           asp-action="ExternalLogin"
                           asp-route-provider="@provider.AuthenticationScheme"
                           asp-route-returnUrl="@Model.ReturnUrl">
                            @provider.DisplayName
                        </a>
                    </li>
                }
            </ul>
        </div>
    </div>
}

This then calls the action method which does the Azure AD login.

public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
	// Request a redirect to the external login provider.
	var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
	var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
	return Challenge(properties, provider);
}

When the login from Azure AD returns, ASP.NET Core Identity is then used to register the user, or complete the login, for example using TOTP 2FA which is part of Identity. If you are using existing accounts, and need to map these to the Azure AD login, this can be done in the user profile.

Now you have full control over the claims, identities and can still use the Azure AD from any tenant with little configuration.

Links:

https://portal.azure.com

http://docs.identityserver.io/en/release/quickstarts/4_external_authentication.html

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.1&tabs=visual-studio

https://joonasw.net/view/azure-ad-authentication-aspnet-core-api-part-2

https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-openid-connect-code

6 comments

  1. […] Implementing a multi-tenant OIDC Azure AD external login for IdentityServer4 – Damien Bowden […]

  2. Thanks for posting!

  3. Akshay Chhangani · · Reply

    How can we validate the token in the ExternalLoginCallback mehtood ..?
    And please elaborate this :

    When the login from Azure AD returns, ASP.NET Core Identity is then used to register the user, or complete the login, for example using TOTP 2FA which is part of Identity. If you are using existing accounts, and need to map these to the Azure AD login, this can be done in the user profile.

    And also how do we come to know that authentication was successful or not?

  4. I don’t see the relation of IdentityServer4 with Azure Active Directory. How they are tied?

  5. Thanks for posting!
    I have a question.

    The client application (asp core with identity server) be notified somehow, in order to invalidate the session if the user is changing the password in AD?

    Thanks,
    Andrei

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: