Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Identity-as-a-Service (IDaaS) : Okta and ASP.Net Core

DZone's Guide to

Identity-as-a-Service (IDaaS) : Okta and ASP.Net Core

In this post, we show just how easy it is to get a functioning login system up an running on your ASP.NET Core app to ensure user authentication.

· Security Zone ·
Free Resource

Protect your applications against today's increasingly sophisticated threat landscape.

In the previous article, we discussed identity as service providers — Identity-as-a-Service — AWS Cognito and Okta. Now let’s see how we can use one of them, Okta, with an ASP.NET Core web application.

For this example, we only need an email account and Visual Studio. The Community version is more than enough.

All code for this example is available on GitHub.

Web App

First, we create a web application in ASP.NET Core in Visual Studio 2017. In this case, the app that gets created by default is enough. Configuring Authentication in ASP.NET Core 2.0 is very simple, most of the changes occur in the startup.cs file. But before we start setting up the app, we have to have our Identity-as-a-Service. Let’s start with the configuration in Okta.

Okta — New Account

On the Okta Developer site, you can create a new account. After completing the form, it shows us the welcome message. We also received an email from Okta to confirm our account and the temporary password to access our new account.

After confirming, changing the password, and other answering other security questions, we have access to the console, which includes the links to Okta’s quick start guides for different front-end and backend technologies.

The first thing we have to do next is to create the entry of our app, to allow it to contact Okta to identify the users. This is achieved from the Applications menu, then, on that page, press the Add Application button. The selection of the application type directly impacts the OAuth flow that will be used in the app. For example, SPA — Single Page App — only allows implicit since the JavaScript is vulnerable to other types. For this example, we are going to choose the Web type and use the Authorization Code flow, which is the default option.

The form to create the app has two values to configure: Base URIs and Login redirect URIs. Although the guide mentions another value, Logout redirect URI, we can not modify it until later when the app has been created. These three values depend on the configuration of our web app, mainly the port where it will run on localhost.

Something that, in the past, needed to be done and that Okta now does automatically at the time of creation is to assign the domain to the Trusted Origins list. But if, for some reason, we have to change the domains of our app, we must make the change manually not only in the app in Okta but also in the menu option, API > Trusted Origins.

Configuration Values

After the creation of the app in Okta, we can go back to Visual Studio.

The necessary data to be able to configure are the Client ID and Client Secret that we can access when we enter the configuration of the app in Okta. Although from this section we cannot change the Client ID, we can generate a new Client Secret if necessary. Another value required to complete the configuration is the domain of the Authority. That is the domain that Okta provides us. Although the guide mentions it, I did the following more than once.

Do not include -admim in the domain.
The correct domain is dev-639799.oktapreview.comand not dev-639799-admin.oktapreview.com

This domain is very important since it is where we get all the OAuth and OIDC settings from our Okta account, including the link where the JSON Web Key Set (JWKS) is obtained to validate the tokens. To see this information, we can call the following URL from Postman, for example.

https://dev-639799.oktapreview.com/oauth2/default/.well-known/openid-configuration

Startup.cs Changes

The first changes that are necessary to make are to using

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Options;

Most of the changes are in the ConfigureServices method. Some comments before viewing the code, particularly when it is different from the Okta guide.

First, instead of harcoding the properties of the OIDC connection in the code, we use appsettings.json or more flexibility.

Then, as we are using Razor Pages, the way to indicate which resources to protect is different, using the AuthorizePage method, in this case only on the Index page.

The third section has two parts, AddAuthentication to indicate the Authentication andAddOpenIdConnect schemes to indicate the parameters of the OIDC connection, by far the most important section of the code.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<OpenIdConnectOptions>(Configuration.GetSection("Authentication:Okta"));

    var serviceProvider = services.BuildServiceProvider();
    var authOptions = serviceProvider.GetService<IOptions<OpenIdConnectOptions>>();

    services.AddMvc()
        .AddRazorPagesOptions(options => {
             options.Conventions.AuthorizePage("/Index");
         });

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(options =>
    {
        options.ClientId = authOptions.Value.ClientId;
        options.ClientSecret = authOptions.Value.ClientSecret;
        options.Authority = authOptions.Value.Authority;
        options.CallbackPath = authOptions.Value.CallbackPath;
        options.ResponseType = authOptions.Value.ResponseType;
        options.SaveTokens = authOptions.Value.SaveTokens;
        options.UseTokenLifetime = authOptions.Value.UseTokenLifetime;
        options.GetClaimsFromUserInfoEndpoint = authOptions.Value.GetClaimsFromUserInfoEndpoint;
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.TokenValidationParameters =
        new TokenValidationParameters
        {
            NameClaimType = authOptions.Value.TokenValidationParameters.NameClaimType
        };
    });
}

And, finally, modify the Configure method to use the Authentication model that we configured in the previous step.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();

    // The rest of the Configure Method
}

When we run the app, it automatically takes us to the Okta’s Sign In page since, to access the Index page, we need an authenticated user. Unlike Cognito, we do not have the option to register a new user in the form. Although Okta provides an API to build our own registry.

In this case, we can use the same user with whom we created the account and the app in Okta.

After filling in the username and password, Okta sends us back to our app. If we are interested in doing something in particular after receiving authorization from Okta, such as showing notifications since the user last accessed the app, the OnAuthorizationCodeReceived event can be used.

Final Words

The configuration of the service in ASP.NET Core 2.0 is very simple and, in a short time, we can be developing our app without worrying about security or managing the users ourselves. This case shows the basic configuration for Okta but the truth is that any other OIDC service requires a similar amount of effort.

Thanks for reading!

{
  "Authentication": {
    "Okta": {
      "Authority": "https://dev-639799.oktapreview.com/oauth2/default/",
      "CallbackPath": "/authorization-code/callback",
      "ClientId": "{clientId}",
      "ClientSecret": "{clientSecret}",
      "GetClaimsFromUserInfoEndpoint": true,
      "IncludeErrorDetails": true,
      "MetadataAddress": "https://dev-639799.oktapreview.com/oauth2/default/.well-known/openid-configuration",
      "RequireHttpsMetadata": false,
      "ResponseType": "code",
      "SaveToken": true,
      "TokenValidationParameters": {
        "NameClaimType": "name"
      },
      "UseTokenLifetime": false
    }
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

All views expressed are my own and do not represent opinions of any entity whatsoever with which I have been, am now, or will be affiliated.

Rapidly detect security vulnerabilities in your web, mobile and desktop applications with IBM Application Security on Cloud. Register Now

Topics:
identity as a service ,security ,authentication ,web application security ,appsec

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}