.NET Core


Table of Contents:

Prerequisites
Dependencies
Note on hosting
.NET Core SDK Setup
Run the .NET Core Demo Apps
Setting up an outbound HTTP Proxy Server
Sample apps code analysis
Making a web app available as an authenticator for a mobile app


Prerequisites

Creating an app involves two basic steps:

  1. Register/create an app in the portal and obtain credentials (this is detailed in the 'Create a New App' menu section)
  2. Configure your app using an SDK, making use of these credentials

It is recommended that you first create a demo/test app with two redirect urls of http://127.0.0.1:5000/login and http://127.0.0.1:65318/login in the portal, to enable you to run the SDK demo apps and test the SDK functionality.

In the portal, when you create a new app, you will be issued with the client ID and client secret credentials that you need to specify when building your app with the SDK. These are found in the app settings screen:

app settings page

Note that you can control the Login Methods available (QR Code requires customer usage of the mobile app. While Browser Login enables logging in within the desktop browser, without the mobile app)


Dependencies


Two versions of the .NET Core SDK are available: version 1 (supports version 1 of .NET Core) and version 2 (supports version 2 of .NET Core). They are available to clone or download from https://github.com/miracl/maas-sdk-dotnet-core1 and https://github.com/miracl/maas-sdk-dotnet-core2

The SDK has the following dependencies:

  1. .NET Core version 1 or 2
  2. MS Visual Studio 2017 and above

Note on hosting


Please note that, for demo purposes, this documentation shows the use of IIS Express. This is for local testing purposes, and you should use your own chosen method to host a publicly-available web app.


.NET Core SDK Setup


  1. Navigate to your chosen working projects folder and clone the repository git clone https://github.com/miracl/maas-sdk-dotnet-core1.git (or git clone https://github.com/miracl/maas-sdk-dotnet-core2.git for version 2) or download and extract the zip file from the repository url.

  2. Navigate to the root maas-sdk-dotnet-core folder, then open Authentication.sln with Visual Studio

  3. Right-click on the top-level 'Authentication' solution and choose 'Build Solution'.

Run the .NET Core demo apps


There are two demo apps configured within the repository. The one we have called a 'Manual' authentication app makes use of the MIRACL Trust® API to give detailed 'granular' control over how the authentication is configured; while the one we have called an 'External' authentication app makes use of Microsoft's standard approach to setting up a simple external ASP.NET Core application with an external authentication provider.

Choose a tab to view the instructions for running either the 'manual' demo app or the simple 'external' demo app:

In Visual Studio:

  1. Right-click on the 'MiraclAuthenticationApp.Core2.0' folder and choose 'Set as Startup Project'.

  2. Open the appsettings.json file in MiraclAuthenticationApp.Core2.0 and edit the following section to insert your app credentials:

    "zfa": {
        "ClientId": "CLIENT_ID",
        "ClientSecret": "CLIENT_SECRET"
    }

    For security, the client ID and secret for a genuine app should not be stored in clear text in a config file. This has only been done here for simple demo purposes. For a production scenario, the client ID and secret should be programmatically accessed via an encrypted API You can also use the recommended approach by Microsoft**

  3. Then open the MiraclAuthenticationApp.Core2.0/Views/Home/Index.cshtml file and, towards the end of the file, make sure the mpad script has the correct url in order to communicate with the authentication server (note that it begins with 'mcl.cdn.mpin.io'):

    @section scripts{
    <script src="https://mcl.cdn.mpin.io/mpad/mpad.js"  data-authurl="@ViewBag.AuthorizationUri" data-element="btmpin"></script>
    }
  4. Now run the app (ctrl + f5) and it will be automatically opened on port 5000 in your browser:

    example-login

    You will notice a tick box which enables you to use the 'preroll id' login facility:

    use preroll id

    This means that a user can enter their email address and it will be automatically baked into the QR code. When the QR code is scanned with the phone app, this will save having to re-input their email address and have one of two effects:

    1. If you are not already registered with the service, you will automatically be sent a confirmation email
    2. If already registered, your ID that has been registered with that email address will be automatically selected

    Once you click the login button, you will be prompted to confirm your identity (if not already registered), create a 4-digit PIN and login.

    Once logged in you will be greeted by the logged in session page:

    example-logged-in

In Visual Studio:

  1. Right-click on the 'MiraclExternalAuthenticationApp.Core2.0' folder and choose 'Set as Startup Project'.

  2. Open the appsettings.json file in MiraclExternalAuthenticationApp.Core2.0 and edit the following section to insert your app credentials:

    "zfa": {
        "ClientId": "CLIENT_ID",
        "ClientSecret": "CLIENT_SECRET"
    }

    For security, the client ID and secret for a genuine app should not be stored in clear text in a config file. This has only been done here for simple demo purposes. For a production scenario, the client ID and secret should be programmatically accessed via an encrypted API. You can also use the recommended approach by Microsoft

  3. Before running the app it is necessary to migrate the application database. This can be done in Visual Studio by using the Package Manager console and running PM > Update-Database:

    Insert image

  4. Now run the app (ctrl + f5) and it will be automatically opened on port 65318 in your browser. You can then click on Log in to the right of the top menu bar (note that you will be prompted to trust the self-signed SSL certificate which is automatically generated by IIS Express):

    ext-login-1

    On the Log in page, you can then click on the MIRACL button under 'Use another service to log in':

    ext-login-2

    You will then be presented with the 'mpad' login screen where you can set up a pin via mobile app or the browser. Once authenticated you will be greeted with the final registration screen, which adds the user to the SQL database for the .NET Core application (this database is not part of the MIRACL Trust® authentication platform, but serves as an example of how a website user database might be used in conjunction with the authentication service)

    ext-login-3


Setting up an outbound HTTP Proxy Server


In order to make the SDK or the Sample Web Apps work using a proxy server, the Windows Internet configuration options can be changed as such:

  1. Go to Control Panel -> Network and Internet -> Internet Options
  2. Select the Connections tab and the click the LAN Settings button
  3. Select the option Use a proxy server for your LAN and specify the desired proxy server Address and Port
  4. Click the OK button

The SDK and the Sample app should then work through the specified proxy server.


Sample Apps Code Analysis


Choose a tab to view the code analysis for either the 'manual' authentication demo app using the MIRACL Trust® API, or for the simple default 'external' authentication demo app:

  1. Setting the baseUri and redirect url

    In MiraclAuthenticationApp.Core2.0/Properties/launchSettings.json the urls for the application are set. Note that for the demo app the important settings are the IIS Express settings which set the applicationUrl and launchUrl as http://127.0.0.1:5000:

    {
    "iisSettings": {
      "windowsAuthentication": false,
      "anonymousAuthentication": true,
      "iis": {
        "applicationUrl": "http://localhost/MiraclAuthenticationApp.Core2.0",
        "sslPort": 0
      },
      "iisExpress": {
        "applicationUrl": "http://127.0.0.1:5000",
        "sslPort": 0
      }
    },
    "profiles": {
      "IIS Express": {
        "commandName": "IISExpress",
        "launchBrowser": true,
        "launchUrl": "http://127.0.0.1:5000/",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        }
      },
      "MiraclAuthenticationApp": {
        "commandName": "Project",
        "launchBrowser": true,
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        },
        "applicationUrl": "http://localhost:51064/"
      }
    }
    }

    By appending the miraclClient.CallbackString property (/login) to the baseUri, the SDK will automatically create the redirect url. In this demo the SDK picks up the baseUri as http://127.0.0.1:5000 which means that the redirect url will be set as http://127.0.0.1:5000/login.

  2. Dealing with the Miracl Client object

    As mentioned above the Client ID and Client Secret are set in the MiraclAuthenticationApp.Core2.0/appsettings.json file:

    "zfa": {
    "ClientId": "CLIENT_ID",
    "ClientSecret": "CLIENT_SECRET"
    }

    The MiraclClient is created by the /Controllers/HomeController.cs file.

    Here you can see that, when called, the client is initiated with the client id and client secret by using Startup.Configuration and the zfa parameters as stored in appsettings.json:

    internal static MiraclClient Client;
    public async Task<IActionResult> Index()
    {
      var url = Request.Scheme + "://" + Request.Host.Value;
      ViewBag.AuthorizationUri = await GetUrl(url);
      return View();
    }
    
    internal static async Task<string> GetUrl(string url)
    {
      if (Client == null)
      {
          Client = new MiraclClient(new MiraclOptions
          {
              ClientId = Startup.Configuration["zfa:ClientId"],
              ClientSecret = Startup.Configuration["zfa:ClientSecret"],
              SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,                     
              SaveTokens = true
          });
      }
    
      return await Client.GetAuthorizationRequestUrlAsync(url);
    }

    It is also important to note that, as per using Microsoft.AspNetCore.Authentication.Cookies; and SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme, the app uses Cookies as the Authenticaton Type.

    ViewBag.AuthorizationUri = await GetUrl(url); and return await Client.GetAuthorizationRequestUrlAsync(url); are used to obtain and send the authorization request url which can then, in the .cshtml files which control the front end of your app, be used with mpad.js to send authentication parameters (client_id and redirect_uri) to the server.

    In /Controllers/loginController.cs the client.ValidateAuthorization(Request.Query) method is used to complete the authorization query. This will either return null if authorization is denied, or will return an access token on success:

    if (Request.Query != null && !string.IsNullOrEmpty(Request.Query["code"]) && !string.IsNullOrEmpty(Request.Query["state"]))
    {
      var properties = await HomeController.Client.ValidateAuthorization(Request.Query);
      ClaimsPrincipal user;
      if (properties != null)
      {
          user = await HomeController.Client.GetIdentity();
          await Request.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
      }
    
      var idToken = properties.GetTokenValue(OpenIdConnectParameterNames.IdToken);
      if (!string.IsNullOrEmpty(idToken))
      {
          ViewBag.IdentityTokenParsed = ParseJwt(idToken);
      }
      var accessToken = properties.GetTokenValue(OpenIdConnectParameterNames.AccessToken);
      if (!string.IsNullOrEmpty(accessToken))
      {
          ViewBag.AccessTokenParsed = ParseJwt(accessToken);
      }
      var refreshToken = properties.GetTokenValue(OpenIdConnectParameterNames.RefreshToken);
      if (!string.IsNullOrEmpty(refreshToken))
      {
          ViewBag.RefreshTokenParsed = ParseJwt(refreshToken);
      }
      var expiresAt = properties.GetTokenValue(Miracl.Constants.ExpiresAt);
      if (!string.IsNullOrEmpty(expiresAt))
      {
          ViewBag.ExpiresAt = expiresAt;
      }
    }  

    In the above code it can be seen that the ClaimsIdentity object which is necessary for the user to authenticate is created by:

    {
      user = await HomeController.Client.GetIdentity();
      await Request.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
    }

    Using ViewBag.Client = HomeController.Client; before the result is returned within public async Task <ActionResult> Index() makes the @ViewBag.Client.UserId and @ViewBag.Client.UserEmail properties available in the login/Index.cshtml file:

    ViewBag.Client = HomeController.Client;
    return View();            
    }

    In Controllers/HomeController.cs, Request.HttpContext.SignOutAsync() can then be used to log the user out, with client.ClearUserInfo() being used to specify whether all client settings (including options (credentials), state and nonce) are cleared or not:

    if (Logout != null)
    {
      Client.ClearUserInfo(false);
      await Request.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
  3. Notes on the index.cshtml files

    The login page of the demo app is configured in /Views/Home/Index.cshtml. It makes use of User.Identity.IsAuthenticated to check if the user is already logged in. If not then the login button is created:

    if (User.Identity.IsAuthenticated)
    {
       <button name="Logout" id="LogoutId" title="Test" value="Logout">Logout</button>
    }  
    else
    {
        <div class="inner cover">
            <p class="lead">
                <a id="btmpin"></a>
            </p>
            <p>
                @Html.CheckBox("UsePrerollId") &nbsp; Use PrerollId login
                <div hidden="hidden">
                    <label for="PrerollId" id="lblPrerollId">PrerollId</label>:
                    <br />
                    @Html.TextBox("PrerollId", string.Empty, new { style = "width:500px" })
                </div>
            </p>
        </div>
    }

    Note that the use of <a id="btmpin"></a> is what creates the login button in communication with the mpad.js script.

    Note also that the use of PrerollId will enable capturing the user's email address to bake it into the QR code. Ultimately, it will then be pre-populated in the user's phone app, saving them the trouble of entering their email address twice and enhancing the user experience. At the end of the Home/Index.cshtml file there is a $("#UsePrerollId") javascript which is needed for PrerollId to function.

    The mpad.js library is used to construct the login button:

    @section scripts{
      <script src="https://mcl.cdn.mpin.io/mpad/mpad.js"  data-authurl="@ViewBag.AuthorizationUri" data-element="btmpin"></script>
      }

    Where:
    data-element is the login button ID (note that this must correspond with <a id="btmpin"> in order for the button to work)
    data-authurl is the authorization URL (this passes the client_id and redirect_uri to the authentication server). As mentioned above, this was fetched with the Client.GetAuthorizationRequestUrlAsync method and sent by ViewBag.AuthorizationUri = url;.

    The logged in session page which presents the refresh/logout options is configured in Views/login/Index.cshtml. Note that the name of the view (login) is the same as the callback path of the server (specified in the redirect uri: baseUri/login) and handles the response of the server.

    Here the 'logout' button is created:

    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        <button name="Logout" id="LogoutId" title="Test" value="Logout" type="submit">Logout</button>
    }

    Also, thanks to using ViewBag.Client = HomeController.Client; in loginController.cs, @ViewBag.Client.UserId and @ViewBag.Client.UserEmail can be used to return the email address and ID of the registered user, as in the sample:

    Hi, <b>@ViewBag.Client.UserId</b> !

    Important Note on User Management

    In terms of managing your users, it is important to note that, in the process of providing a secure login solution, the service has also registered your users with a confirmed user email and user ID. Once a user has been authenticated it is possible to make use of the HomeController.Client.UserId and HomeController.Client.UserEmail properties to return string values.

    This removes a considerable amount of pain from the process of managing users and databases!

    For example, if you have a SQL user database and you want to make a check to see if a user is present, or needs added as a new user, then it is possible to make use of the above properties.

    Another example would be if you want to present a web form to capture more information that is needed to provide a user with access to your product features. Here you can use the above properties to prepopulate the ID and email address field, and you do not need to initiate a 'verify by email' process, as this has already been done by the service.

The external authentication demo app was set up as an ASP.NET Core project as per the Microsoft documentation for enabling external authentication.

For both .NET Core versions 1 and 2, configuring MIRACL Trust® as an external authentication provider is a simple case of editing the Startup.cs file. The edits to be made differ slightly for each version:

Version 2.x

Add the MIRACL Trust® authentication service to the ConfigureServices method in the Startup.cs file:

services.AddAuthentication()
        .AddMiracl(Constants.AuthenticationScheme, o =>
        {
            o.ClientId = Configuration["zfa:ClientId"];
            o.ClientSecret = Configuration["zfa:ClientSecret"];
        });

This will then pick up the ClientId and ClientSecret from the appsettings.json file, as mentioned above.

Version 1.x

Add the MIRACL Trust® middleware in the Configure method in the Startup.cs file:

app.UseMiraclAuthentication(new MiraclOptions
{
    SignInScheme = new IdentityCookieOptions().ExternalCookieAuthenticationScheme,
    ClientId = Configuration["zfa:ClientId"],
    ClientSecret = Configuration["zfa:ClientSecret"]
});

This will then pick up the ClientId and ClientSecret from the appsettings.json file, as mentioned above.

Top