.NET Pluggable Verification


Table of Contents:

Create an app in the admin portal
Run the demo Pluggable Verification app
Demo apps analysis
| ---- Full Custom Push
| ---- Full Custom Pull
| ---- Custom Email


With the .NET SDK it is possible to configure 'Pluggable Verification' which enables you to configure custom methods for verifying users who are signing up to your service, beyond the default email confirmation process.


Dependencies


Note that the SDK has the following dependencies:

  1. .NET framework 4.5.2 and above
  2. MS Visual Studio 2013 and above
  3. IdentityModel (NuGet package)

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.


Note on using PV in mobile applications


Note that if you are wanting to configure a fully custom (push or pull) PV setup for users of mobile authentication apps, all of the logic must be configured as a backend service, so happens outside of the app itself.

 


Create an app in the admin portal


Note that the Pluggable Verification settings in the admin portal are not currently available for customers. These have to be set at a global level. If you wish to make use of Pluggable Verification please contact us using our chat facility, or email us at support@miracl.com.

When logged into the authentication portal and looking at the company settings tab, you can choose which type of verification you wish to use (note that this is set at company level and not at app level):

add client

Of key importance here is the Verification URL. For both customEmail and Fully Custom Push this needs to be set:

For Custom Email you should set the Verification URL to http://<<yourpublicip>>:5100/customEmail

For Full Custom Push you should set the Verification URL to http://<<yourpublicip>>:5100/push (Note that 'Full Custom Push' requires a url which is hosted publicly, not on a closed internal network)

For Full Custom Pull you do not need to set the Verification URL

 

The Verification Method options are:

  1. Standard Email - This is the default verification system whereby an email is sent to the registering user which contains a link to an automatically set confirmation url that talks to the MIRACL Trust authentication server. The id of the user is verified and activated, before they proceed to set up their PIN.

  2. Custom Email - This can be used to configure a setup whereby an email which contains a link to the custom Verification URL (as set above) is sent to the registering user. Custom logic can be implemented at this url to allow the user to verify and activate their id with the authentication server (an access code, upload of photographic ID, etc.). The user will then be able to set up their PIN.

  3. Fully Custom - This is for customers wanting to use a full custom verification setup for a custom-built application (i.e. nothing is sent by email to the registering user). For this there are a further two options for New User Notification Type:
    • Push - here the MIRACL Trust authentication server sends a request to the Verification URL when an identity starts a registration to it and there the identity is verified and activated before the PIN can be setup
    • Pull - here the customer's application sends a request to the MIRACL Trust authentication server to check if a registration for this identity has started. If so, a custom logic can be used to verify and activate the user before they continue to setup their PIN

In Pre Custom Text you can set the instructions given to the user before they enter their identity (screenhsots will be given below)

In Post Custom Text you can set the instructions given to the user after they enter their identity (screenhsots will be given below)

For fully custom, Identity Type can be used to set whether the identity is an email address or alpha-numeric ID such as an account number

 


Run the demo Pluggable Verification app


In order to make use of the Pluggable Verification demo app you should download version 2 of the .NET SDK repo from https://github.com/miracl/maas-sdk-dotnet-v2.git

Then:

  1. In the authentication portal go to Apps > Create New App and create a standard app which includes http://127.0.0.1:5100/login (the app can be locally hosted if not using Full Custom Push) or http://<<yourpublicip>>:5100/login (if using Full Custom Push verification) as a redirect url:

app settings page

 

  1. Once you have opened the root folder Authentication.sln file in Visual Studio, navigate back to the root folder and open the .vs/config/applicationhost.config file to edit the MiraclIdentityVerificationApp block:

    <site name="MiraclIdentityVerificationApp" id="3">
     <application path="/" applicationPool="Clr4IntegratedAppPool">
         <virtualDirectory path="/" physicalPath="C:\Users\Mike\sdk\maas-sdk-dotnet-v2\MiraclIdentityVerificationApp" />
     </application>
     <bindings>
         <binding protocol="http" bindingInformation="*:5100:127.0.0.1" />
     </bindings>
    </site>

    Here you need to make sure that bindingInformation, which sets the binding for the IP address of the machine which will be running the app is correct. e.g. "*:5100:127.0.0.1" if you are running a local test, or "*:5100:<<yourpublicip>>" or "*:5100:" to allow binding to any IP.

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

  3. Right-click on '/Samples/MiraclIdentityVerificationApp' and choose 'Set as Startup Project'

    Before running the app, you need to edit the web.config file to contain the Client ID and Client Secret for your app (available in the admin portal as per the above screenshot)- adjusting the relevant section depending on which type of verification you are using.

    <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    
    <add key="StandardEmailClientId" value="CLIENT_ID"/>
    <add key="StandardEmailClientSecret" value="CLIENT_SECRET"/>
    
    <add key="CustomEmailClientId" value="CLIENT_ID"/>
    <add key="CustomEmailClientSecret" value="CLIENT_SECRET"/>
    
    <add key="FullCustomPullClientId" value="CLIENT_ID"/>
    <add key="FullCustomPullClientSecret" value="CLIENT_SECRET"/>
    
    <add key="FullCustomPushClientId" value="CLIENT_ID"/>
    <add key="FullCustomPushClientSecret" value="CLIENT_SECRET"/>
    <add key="FullCustomPushCustomerId" value="CUSTOMER_ID"/>
    </appSettings>

    Note that, for Full Custom Push, FullCustomPushCustomerId is required. This is visible as a tooltip in the top right corner of your company dashboard in the portal:

    view cid

    To activate the login button for each of the custom apps, it is necessary to open Views/Home/Index.cshtml 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>
    }

     


Demo apps analysis


After running the demo app in Visual Studio (ctrl + f5) and visiting http://<<yourpublicip>>:5100/, from the top toolbar you can select the relevant tab for the app you are wanting to test.

The primary SDK methods which are available to manage the verification process are:

  • GetIdentityInfoAsync - used to acquire identity information per its hashMPinId and activateKey
  • ActivateIdentityAsync - activates the identity with the authentication server and enables the user to continue registration and setup their PIN
  • HandleNewIdentityPushAsync - validates the request on the authentication server when Full Custom Push is used. Returns an Identity object
  • HandleNewIdentityPullAsync - when Full Custom Pull is used, asks the authentication server if a registration has been started for the specified identity and returns an Identity for it if so
  • ParseCustomEmailQueryString - parses the query string for Custom Email Verification and returns an IdentityActivationParams object

To view a breakdown of the logic and methods used for each type of verification, select a tab from the options below:

 

The Full Custom Push app

custom email

Note that 'Full Custom Push' requires a url which is hosted publicly, not on a closed internal network.

Clicking on the 'Full Custom Push' tab will display the above page. You can then verify an identity via the following process:

  1. Click on the 'pushController' link and the verify page will open in a new tab. This page will display a list of users that are either awaiting verification or are already verified. It will be empty when you first visit it.

  2. Navigate back to the above page and click 'Login'.

  3. In the PIN pad, enter your ID (email or alpha-numeric depending on what you set in the portal) to start a new user registration:

    enter id

  4. Return to the verify page and you will see your id/email has appeared and is awaiting verification. You can then click on 'Activate' in the status column:

    verification status list

    Your status will then change to 'Activated'

  5. Once activated return to the PIN pad and click 'confirm':

    confirm id

You can then set up a PIN and you will be logged in and greeted with the logged in session page.

Full Custom Push logic explanation

The logic for the verify page is found in the Controllers/pushController.cs file.

The first thing done here is setting up a ViewModel List to receive and display updates on pending and activated users. This List is picked up by Views/push/index.cshtml:

private static List<PushViewModel> Data = new List<PushViewModel>();

public ActionResult Index()
{
    UpdateDataStatus();
    return View(Data);
}

When the authentication server receives a new identity for registering it sends a request to the Verification URL and triggers the IndexPost action. Then the HandleNewIdentityPushAsync SDK method is called with the requested user data to add it to the ViewModel list

[HttpPost]
[ActionName("Index")]
public ActionResult IndexPost()
{
    var newUserJson = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
    var identity = HomeController.Client?.HandleNewIdentityPushAsync(newUserJson);

    if (identity != null && !identity.IsExpired())
    {
        Data.Add(new PushViewModel(identity));
        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }

    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}

When the user clicks the Activate button for an identity on the 'pushController' page, the Activate action takes care of the identity activation:

[HttpPost]
public async Task<ActionResult> Activate(string mPinIdHash)
{
    var d = Data.FirstOrDefault(id => id.Identity.ActivationParams.MPinIdHash == mPinIdHash);
    if (d != null && d.Identity != null && !d.Identity.IsExpired())
    {
        var respStatusCode = await HomeController.Client.ActivateIdentityAsync(d.Identity.ActivationParams);
        if (respStatusCode != HttpStatusCode.OK)
        {
            ViewBag.ErrorMsg = string.Format("Cannot activate identity. Server responded with status {0} {1}.", (int)respStatusCode, respStatusCode);
            return View("Error");
        }

        d.Status = IdentityStatus.Activated;
    }

    return RedirectToAction("Index");
}

Here the ActivateIdentityAsync SDK method is used to activate the user once the button is clicked. If this returns OK the status is updated to 'Activated'.

Within the controller file you will also notice that GetIdentities() is used to update Views/push/_IdentitiesTablePartial.cshtml which creates the formatted html table that is displayed in Views/push/index.cshtml:

public ActionResult GetIdentities()
{
    UpdateDataStatus();
    return PartialView("_IdentitiesTablePartial", Data);
}

This makes use of the UpdateDataStatus method:

private void UpdateDataStatus()
{
    foreach (var d in Data)
    {
        if (d.Status == IdentityStatus.Pending && d.Identity.IsExpired())
        {
            d.Status = IdentityStatus.Expired;
        }
    }
}

The GetIdentities action is called on every two seconds to update the table with users. The logic for this is found in Views/push/index.cshtml:

<script>
    function getList() {
            $.ajax({
            url: "@Url.Action("GetIdentities", "push")",
            type: "GET",
            dataType: "html",
            cache: false,
            success: function (res) {
                $("#identities").html(res);
            }
        })
    }

    setInterval(getList, 2000);
</script>

 

The Full Custom Pull app

custom email

Clicking on the 'Full Custom Pull' tab will display the above page. You can then verify an identity via the following process:

  1. Click on the 'pullController' link and the verify page will open in a new tab.

  2. Navigate back to the above page and click 'Login'.

  3. In the PIN pad, enter your email or alphanumeric ID to start a new user registration.

  4. Return to the verify page, enter your email address or alphanumeric ID in the box and click 'Check' to ask the authentication server if the registration process has started:

    pull verify page

  5. If the registration process has not started or has expired you will receive the following message:

    pull not started

  6. If it has started you will be able to activate:

    pull activate

    and will be greeted with a success message:

    pull success

  7. Once activated return to the PIN pad and click 'confirm'. You can then set up a PIN and you will be logged in and greeted with the logged in session page.

     

Full Custom Pull logic explanation

The logic for the verify page is found in the Controllers/pullController.cs file. It creates a ViewBag which is picked up by Views/pull/index.cshtml and Views/pull/Activate.cshtml

The Index action uses the HandleNewIdentityPullAsync SDK method to check if registration has started for the particular ID:

[HttpPost]
public async Task<ActionResult> Index(string id)
{
    ViewBag.ActivationStarted = false;
    var identity = await HomeController.Client.HandleNewIdentityPullAsync(id);

    if (identity != null && !identity.IsExpired())
    {
        ViewBag.ActivationStarted = true;
        ViewBag.Info = identity.Info;
        StartedRegistration.Add(id, identity);
    }
    else
    {
        if(!string.IsNullOrEmpty(id))
        {
            ViewBag.Id = id;
        }
    }

    return View();
}

Then the Activate action uses the ActivateIdentityAsync method, which activates the identity on the authentication server, enabling the user to continue with registration and setup their PIN:

[HttpPost]
public async Task<ActionResult> Activate(string id)
{
    ViewBag.IsIdentityActivated = false;
    if (StartedRegistration.ContainsKey(id))
    {
        var identity = StartedRegistration[id];

        // check here if the identity is valid and if so, call ActivateIdentityAsync of the current client object
        if (identity != null)
        {
            var resStatusCode = await HomeController.Client.ActivateIdentityAsync(identity.ActivationParams);
            if (resStatusCode == HttpStatusCode.OK)
            {
                ViewBag.IsIdentityActivated = !identity.IsEmpty();
                ViewBag.Info = identity.Info;
                StartedRegistration.Remove(id);
            }
        }
    }
    return View();
}

Then, in Views/pull/index.cshtml, an @if (!ViewBag.ActivationStarted) check is made. If it has not started the user is asked to input their email and click 'Check':

@if (!ViewBag.ActivationStarted)
{
    if (ViewBag.Id != null)
    {
        <p>
            Activation with <strong>@ViewBag.Id</strong> has not started or has expired.
        </p>
    }

    using (Html.BeginForm())
    {
        <p>
            <br />
            <text> Enter the identity you've started the registration with:</text><br /><br />
            <input id="id" type="email" name="id" /><br /><br />
            <input type="submit" value="Check" /><br />
        </p>
    }
}

If it has started then the user is presented with the activation button:

else
{
    <p>
        Click the button below to start using <strong>@ViewBag.Info.Id</strong> as your identity on device <strong>@ViewBag.Info.DeviceName</strong>
    </p>
    using (Html.BeginForm("Activate", "pull"))
    {
        <input type="hidden" name="id" value="@ViewBag.Info.Id" />
        <input type="submit" value="CONFIRM AND ACTIVATE" class="btn btn-primary" />
    }
}

 

In Views/pull/Activate.cshtml an @if (ViewBag.IsIdentityActivated) check is made before displaying the Identity and DeviceName of the user:

<p>
    @if (ViewBag.IsIdentityActivated)
    {
        <h3>Activation successful</h3>

        if (ViewBag.Info != null)
        {
        <p>
            <br />
            <strong>Identity:</strong> @ViewBag.Info.Id <br />
            <strong>Device name:</strong> @ViewBag.Info.DeviceName
        </p>
    }
    <br />
    <text>You can now close this window.</text>
    <br />
}
else
{
    <h3>ACTIVATION FAILED</h3>

    <text>There was a problem with activating your account. <br />
        Press 'Resend email' from your client app to try again.<br /></text>
}

    If you have any issues please contact our support.
    </p>

 

The Custom Email app

custom email

Clicking on login will launch the code pad. When registration is begun a verification email will be sent from the authentication platform. Note that the verification link in this email has the Verification URL as its root:

custom email

This link will then bring up the confirmation page:

custom email

Once activated the success page is displayed:

custom email

Custom Email logic explanation

The logic for the verify page is found in the Controllers/customEmailController.cs file. It creates a ViewBag which is picked up by Views/customEmail/index.cshtml and Views/customEmail/Activate.cshtml

The Index action is called by the authentication server with the necessary registering identity data in the query string. This is parsed with the ParseCustomEmailQueryStringSDK method and passed to the GetIdentityInfoAsync SDK method, which returns the userID and deviceName:

// GET: customEmail
public async Task<ActionResult> Index()
{
    var activationParams = HomeController.Client.ParseCustomEmailQueryString(Request.QueryString);
    if (activationParams != null)
    {
        var info = await HomeController.Client.GetIdentityInfoAsync(activationParams);
        if (info != null)
        {
            var identity = new Identity(info, activationParams, 0);
            StartedRegistration.Add(info.Id, identity);
            ViewBag.Info = info;
        }
    }

    return View();
}

 

In Views/customEmail/index.cshtml, @ViewBag.Info.Id is used to create the 'Confirm and Activate' button:

@{
    ViewBag.Title = "Custom email registration activation";
}

<p>
    <h2>Please confirm your activation</h2>
<p>
    Click the button below to start using <strong>@ViewBag.Info.Id</strong> as your identity on device <strong>@ViewBag.Info.DeviceName</strong>
</p>

@using (Html.BeginForm("Activate", "CustomEmail"))
{
    <input type="hidden" name="id" value="@ViewBag.Info.Id" />
    <input type="submit" value="CONFIRM AND ACTIVATE" class="btn btn-primary" />
}
<br />
    If you have any issues please contact our support.
</p>

When an activate button is clicked, the Activate action calls the ActivateIdentityAsync to activate the identity on the authentication server, enabling the user to continue with registration and setup their PIN:

[HttpPost]
public async Task<ActionResult> Activate(string id)
{
    ViewBag.IsIdentityActivated = false;
    if (StartedRegistration.ContainsKey(id))
    {
        var identity = StartedRegistration[id];
        ViewBag.Info = identity.Info;

        // apply a custom logic here for validating the identity before activating it
        if (ViewBag.Info != null)
        {
            if (await HomeController.Client.ActivateIdentityAsync(identity.ActivationParams) == HttpStatusCode.OK)
            {
                ViewBag.IsIdentityActivated = true;
            }
        }
    }
    return View();
}

Views/customEmail/Activate.cshtml deals with the process once the activation button is clicked, where a ViewBag.IsIdentityActivated check is made:


@{
    ViewBag.Title = "Custom email registration activation";
}

<p>
    @if (ViewBag.IsIdentityActivated)
    {
        <h3>Activation successful</h3> 

        if (ViewBag.Info != null)
        {
        <p>
            <br />
            <strong>Identity:</strong> @ViewBag.Info.Id <br />
            <strong>Device name:</strong> @ViewBag.Info.DeviceName
        </p>
        }
        <br />
        <text>You can now close this window.</text>
        <br />
    }
    else
    {
        <h3>ACTIVATION FAILED</h3>

        <text>There was a problem with activating your account. <br />
        Press 'Resend email' from your client app to try again.<br /></text>
    }

    If you have any issues please contact our support.
</p>

You can of course enter any of your own custom logic to control activation by other factors. An example might be to use one or more activation codes, which may be linked to user databases:

custom email

Top