06 Support for external identity providers in IdentityServer4

06. IdentityServer4 External Providers .NET Core 3.1

January 24, 2020| deblokt| in category Tutorials .Net Core 3.17 comments

You can find the project [here](https://github.com/Deblokt/IdentityServer4Demos.NETCore31/tree/master/06. IdentityServer4 External Providers).

Standard Agreement

All Identity Providers are supported using standard protocols like OpenID Connect, OAuth2, SAML2 and WS-Federation. This could be Okta, it could be Auth0, could be proprietary IdP of a client, could be another IdentityServer4. Take a look at the list of out-of-the-box extensions for “AuthenticationBuilder” for big providers like Azure AD, Microsoft Account, Google, Facebook, Twitter, etc here https://docs.microsoft.com/en-us/dotnet/api/microsoft. aspnetcore.authentication.authenticationbuilder?view=aspnetcore-2.2

All identity providers support the use of standard protocols such as OpenID Connect, OAuth2, SAML2, and WS-Federation. They can be Okta, Auth0, an IdP dedicated to a certain client, or even another IdentityServer4. Check out the list of out-of-the-box AuthenticationBuilder for big providers like Azure AD, Microsoft Account, Google, Facebook, Twitter and more. List address: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationbuilder?view=aspnetcore-2.2

Setting up the usual OpenID Connect OIDC middleware is enough for most of the providers to get you going. Almost all providers nowadays provide OIDC, some as a second option alongside SAML2 and/or WS-Fed.

For usage, setting up the generic OpenID Connect OIDC middleware is sufficient, almost all providers currently support OIDC, some also support both SAML2 and/or WS-Fed.

As IdentityServer4 is OIDC Identity Provider you can actually set up one IdentityServer4 instance to be an external provider for another IdentityServer4 instance using OIDC middleware. As long as there is a single root node, all Identity Servers connected this way can achieve SSO.

Since IdentityServer4 is an OIDC identity provider, you can indeed use OIDC middleware to set up an IdentityServerr4 as an external provider for another IdentityServer4. By using it as a single root node, SSO is enabled for all Identity servers that connect to it that way.

Azure AD Example

I will continue from my last tutorial. Open the “Quickstart” solution in Visual Studio.

Open the “Startup.cs” in project root and navigate right above the “AddIdentityServer” service registration. Add the authentication middleware for AzureAD like so:

We can continue the previous tutorial and open the Quickstart workaround in Visual Studio.

Open the Startup.cs file in the project, find the AddIdentityServer service registration, and add the registration of the authentication middleware for AzureAD, as shown below:

services.AddAuthentication()
  .AddOpenIdConnect(
  "azuread",
  "Azure AD",
  options => Configuration.Bind("AzureAd", options));

services.Configure<OpenIdConnectOptions>(
  "azuread",
  options => {
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Events = new OpenIdConnectEvents() {
      OnRedirectToIdentityProviderForSignOut = context => {
        context.HandleResponse();
        context.Response.Redirect("/Account/Logout");
        return Task.FromResult(0);
      }
    };
  });

Now open the “appsettings.json” in project root and modify it to add the Azure AD configuration we are using and binding in “Startup” like so:

Then, open the appsettings.json file in the project, modify and add the Azure AD configuration we used in Startup as follows:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\MSSQLLocalDB;Database=IdentityServerQuickstart.NetCore3.1;Trusted_Connection=True;MultipleActiveResultSets=true" },
  "AzureAd": {
    // Authority/MetadataAddress format (https://{instance}/{tenantId}/...
    "Authority": "https://login.microsoftonline.com/0366c849-xxxx-xxxx-xxxx-adcc0ccf2170/oauth2/v2.0/",
    "MetadataAddress": "https://login.microsoftonline.com/0366c849-xxxx-xxxx-xxxx-adcc0ccf2170/.well-known/openid-configuration",
    "ClientId": "7adeb3b0-xxxx-xxxx-xxxx-a6bc5aa756da",
    "CallbackPath": "/signin-oidc"
  }
}

Note You must obtain your TenantId and ClientId (also known as ApplicationId) through the Azure portal. Here is the official documentation on how to create an app in Azure AD: https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app

Tip For app registration, you will need ReturnUrl. For this demonstration, the return URL is http://localhost:5000/signin-oidc

Okta Example

Open the “Startup.cs” in project root and navigate right below the “AddAzureAD” and add:

Open Startup.cs in the project root directory, navigate to the bottom of AddAuzreAD and add:

.AddOpenIdConnect("okta", "Okta", options => Configuration.Bind("Okta", options));

Also add the OpenIdConnectOptions service configuration like so:

You also need to add the configuration of the `OpenIdConnectOptions service as follows:

services.Configure<OpenIdConnectOptions>(
  "okta", options => {
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Events = new OpenIdConnectEvents() {
      OnRedirectToIdentityProviderForSignOut
        = context => {
        context.HandleResponse();
        context.Response.Redirect("/Account/Logout");
        return Task.FromResult(0);
      }
    };
  });

So full code including Azure Ad and Okta looks like so:

So, the complete code including support for Azure Ad and Okta looks like this:

services.AddAuthentication()
  .AddOpenIdConnect(
  "azuread",
  "Azure AD",
  options => Configuration.Bind("AzureAd", options)
)
.AddOpenIdConnect(
  "okta",
  "Okta",
  options => Configuration.Bind("Okta", options)
);

services.Configure<OpenIdConnectOptions>(
  "azuread",
  options => {
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Events = new OpenIdConnectEvents() {
      OnRedirectToIdentityProviderForSignOut =
        context => {
        context.HandleResponse();
          context.Response.Redirect("/Account/Logout");
          return Task.FromResult(0);
      }
    };
  });

services.Configure<OpenIdConnectOptions>(
  "okta",
  options => {
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Events = new OpenIdConnectEvents() {
      OnRedirectToIdentityProviderForSignOut = context => {
        context.HandleResponse();
        context.Response.Redirect("/Account/Logout");
        return Task.FromResult(0);
      }
    };
  });

Now open the “appsettings.json” in project root and modify it to add the Okta configuration we are using and binding in “Startup” like so:

Now, open the appsettings.json file in the project root directory, modify and add the Okta configuration information we used in Startup.

"Okta": {
  "Authority": "https://dev-xxxxxx-admin.oktapreview.com",
  "ClientId": "0oakhxxxxxxxxxxaX0h7",
  "CallbackPath": "/signin-oidc-okta"
}

Note You must obtain your Authority and ClientId from Okta. Here is the official documentation on how to create an Okta app: https://developer.okta.com/docs/guides/add-an-external-idp/microsoft/register-app-in-okta/

Tip You need to provide a ReturnUrl for app registration, for this demo the return URL is: http://localhost:5000/signin-oidc-okta

Modify the user auto-provisioning process

Adjust the user’s automatic configuration processing

Because we added the “IsEnable” custom property in the previous tutorial the auto-provisioned user will by default have value “false” (disabled user) and the external provider login will fail. We need to slightly modify the automatic user creation process for external providers to set the “IsEnabled” flag to “true”. Navigate to “Quickstart/Account/ExternalController.cs” and open it.

Find the “AutoProvisionUserAsync” method and modify the line that instantiates new user. We need to modify it to set the “IsEnabled” user property to “true” like so:

Since we added a custom IsEnable property for the auto-provisioned user in the previous tutorial, with a default value of false (disabled user), the external provider login will fail. We need to slightly adjust the automatic user creation handling for external providers, setting the IsEnabled flag to true. Find “Quickstart/Account/ExternalController.cs” and open it.

var user = new ApplicationUser{
  UserName = Guid.NewGuid().ToString(),
  Email = email,
  IsEnabled = true
};

Now run the IdentityServer4 and try to sign in with Azure AD or Okta. If the local user exists with the same username or email as the external user (from Azure AD or Okta in our example) the matching process will link the external user with local user and the new local user will not be created. For other scenarios (no match) the auto-provisioning process will create a new local user and link it with the external user. I logged in using Okta and the new local user was auto- provisioned. Notice that my name was automatically populated from the claims provided by Okta. These are the claims of the external user now set to the local user.

Now, run IdentityServer4 and try to log in via Azure AD or okta. If there is a local user with the same username or email for an external user (from Azure Ad or Okta), the matching process will link the external user to the local user and will not create a new local user. For other scenarios (unmatched users), the automatic matching process will create a new local user and link to the external user. I log in with my Okta user and the auto-matching process will be handled automatically. Note that my name will be automatically populated from the claim provided by Okta. Claims from external users are now set to the local user.

Capture

very simple

Now that was super easy, wasn’t it? Adding any standard Identity Provider shouldn’t pose any challenge as the method is pretty much the same. In my next tutorial I will start tackling one of the important features which are Multi-Factor Authentication MFA aka 2FA if there are two factors. Stay fresh!

You can find the project [here](https://github.com/Deblokt/IdentityServer4Demos.NETCore31/tree/master/06. IdentityServer4 External Providers).

Super simple, right? Adding any standard identity provider is no more difficult than these methods. In the next tutorial, I will start with another important feature: multi-factor authentication MFA, also known as 2FA if there are only two factors.

Support

For direct assistance schedule a technical meeting with Ivan to talk about your requirements. For a general overview of our services and a live demo schedule a meeting with Maja.

https://deblokt.com/2020/01/24/06-identityserver4-external-providers-net-core-3-1/