Documentation

Implement the "Login with NxtPort" into your application

Login with NxtPort

 

Introduction

This how-to describes the steps required to implement a "login with nxtport" feature
in your software or webapp

We use IdentityServer v4 as our OAuth2 & OpenId solution.
This is a widely used STS with a lot of documentation & blog posts available on the web.

 

Login using the NxtPort Login screen (recommended)

Step 1 – Register with NxtPort

For registration on the NxtPort platform, go to 

If you want to register on another environment please contact support@nxtport.com.

 

Step 2 – Consider which type of authorization flow you want to use

There are 2 possible flows supported by NxtPort if you want to implement our login screen in your application, depending on the type of client:

  • Public client → Authorization code flow with PKCE

  • Confidential client → Authorization code flow with PKCE or Hybrid flow

What type of client do I have?

Public

A public client is not capable of maintaining the confidentiality of its credentials provided by an authorization server. For example a mobile phone application or a desktop application that has the client secret embedded, could get cracked, and the secret could be revealed. The same is true for a JavaScript application running in the users browser. The user could use a JavaScript debugger to look into the application, and see client credentials.

Confidential

A Confidential client is capable of maintaining the confidentiality of its credentials provided by an authorization server. For example a web application where only the administrator can get access to the server and see the client credentials would be a confidential client.

If you want to learn more about these 2 types of clients, please take a look at the official RFC6749 spec: https://tools.ietf.org/html/rfc6749#page-14

Authorization Code flow with PKCE (public clients)

Summary

   No risk for code substitution attacks
   Simple implementation
   No static secret required
  No additional front-channel response artifacts needed 
 

In Detail
What is PKCE? (Proof Key for Code Exchange - RFC 7636)

This essentially introduces a per-request secret for code flow (please read up on the details here).
The only thing the client has to implement for this, is creating a random string and hashing it using SHA256.

This also solves the substition problem, because the client can prove that it is the same client on front and back-channel, and has the following additional advantages:

  • The client implementation is very simple compared to hybrid flow

  • it also solves the problem of the absence of a static secret for public clients

  • no additional front-channel response artifacts are needed

PKCE is already the official recommendation for native applications and SPAs

Hybrid flow (aka OpenID Connect Hybrid flow, only for confidential clients)

Summary

No risk for code substitution attacks
Uses principle known as "detached signature"
Been around for longer so a lot of documentation available
Requires static secret that needs to be hidden on the client
  Identity token is transmitted and might leak (personal identifiable) data - possible GDPR issue
   More complicated client library implementations

In Detail

This uses a response type of code id_token to add an additional identity token to the response.

This token is signed and protected against substitution.
In addition it contains the hash of the code via the c_hash claim.
This allows checking that you indeed got the right code (experts call this a detached signature).

This solves the problem but has the following down-sides:

  • the id_token gets transmitted over the front-channel and might leak additional (personal identifiable) data

  • all the mitigitation steps (e.g. crypto) need to be implemented by the client. This results in more complicated client library implementations.

The hybrid flow is a well known flow, but was created before GDPR was introduced. The fact that this relies on transmitting an identity-token can be a possible GDPR issue in some countries, where we would recommend to use the Authorization code flow + PKCE.

Step 3 – Contact support and request your client of choice

Create a ticket on our Support desk or send an email to support@nxtport.com with the subject "Request for X client" (where X is either "Authorization Code flow with PKCE" or "Hybrid") with the following content:

  • API: Name of the API you have subscribed to (see step 1).

  • Environment: The environment for which you want a client. Be aware that you already need to be registered and subscribed in this environment (see step 1).

  • Reason: Write one line that briefly explains the context of your request.

  • Base path of web application: Where will the web application be hosted? Usually the first part of the URL with just the hostname. Example: "https://www.example.com"

  • Redirect after login: Where to redirect after a successful login? No wildcards allowed. Example: "https://www.example.com/welcome.html"

  • Redirect after logout: Where to redirect after the user logs out? No wildcards allowed. Example: "https://www.example.com/logged_out.html"

Email template:

To: support@nxtport.com

Subject: Request for X client

  • API: 

  • Environment: 

  • Reason: 

  • Base path of web application: 

  • Redirect after login: 

  • Redirect after logout: 

If your request is accepted by support, you will receive a client-id & -secret which provide you with access to implement a login with nxtport feature in your webapp.

The client-secret is only applicable for hybrid flows.

Step 4 - Implement the NxtPort login flow in your webapp for your client

We recommend using the official libraries provided by the authors of IdentityServer,
this greatly simplifies the implementation and encourages you to implement the flows by following the best practices.

We will provide samples in both .NET Core & Javascript. Samples for other development languages can be found online, or you can always contact our NxtPort support should you require more assistance on the implementation.

.NET Core

Reference OpenIdConnect

Add the following NuGet package to your project to add support for Open ID Connect authentication:

  • Microsoft.AspNetCore.Authentication.OpenIdConnect

In the Constructor of your Startup class, add following line to disable Microsoft legacy mapping for older protocols:

JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

Configure authentication

In the ConfigureServices method of your Startup class, add the following code to enable authentication and configure the NxtPort IdentityServer as the authority:

For Authorization Code flows:

services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie("Cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.Authority = "https://login.nxtport.eu";
                    options.RequireHttpsMetadata = false;

                    options.ClientId = "YourClientId";
                    options.ResponseType = "code";

                    options.SaveTokens = true;
                });

Replace YourClientId with the value provided to you by our Support.

For Hybrid flows: (to be verified)

services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie("Cookies")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.Authority = "https://login.nxtport.eu";
                    options.RequireHttpsMetadata = false;

                    options.ClientId = "YourClientId";
                    options.ClientSecret = "YourClientSecret";
                    options.ResponseType = "code id_token";

                    options.SaveTokens = true;
                });

Replace YourClientId & YourClientSecret with the values provided to you by our Support

Enable authentication

And then to ensure the authentication services execute on each request, add UseAuthentication to the Configure method in the Startup class:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute()
        .RequireAuthorization();
});

 

Note:
The RequireAuthorization method disables anonymous access for the entire application. You can also use the [Authorize] attribute, if you want to specify that on a per controller or action method basis.

For more information, please take a look at the official IdentityServer documentation: http://docs.identityserver.io/en/latest/quickstarts/2_interactive_aspnetcore.html

Javascript

Reference oidc-client

We need a library that works in JavaScript and is designed to run in the browser. The oidc-client library is one such library. It is available via NPM, Bower, as well as a direct download from github.

Include this client in your webapp by referencing to the new client js file:

Configure client

We can use the UserManager class from the oidc-client library to manage the OpenID Connect protocol.
Add this code to configure and instantiate the UserManager:

For Authorization code flows

var config = {
    authority: "https://login.nxtport.eu",
    client_id: "YourClientId",
    redirect_uri: "https://YourHost.com/callback/",
    response_type: "code",
    scope:"openid profile api1",
    post_logout_redirect_uri: "https://YourHost.com/",
};
var mgr = new Oidc.UserManager(config);

The redirect & post-logout redirect Uri's are free to choose as these point to the pages of your webapp where the user should be redirected to after a successful login or logout.

Replace YourClientId with the value provided to you by our Support.

For Hybrid flows (to be verified)

var config = {
    authority: "https://login.nxtport.eu",
    client_id: "YourClientId",
	client_secret: "YourClientSecret",
    redirect_uri: "https://YourHost.com/callback/",
    response_type: "code id_token",
    scope:"openid profile api1",
    post_logout_redirect_uri: "https://YourHost.com/",
};
var mgr = new Oidc.UserManager(config);

The redirect & post-logout redirect Uri's are free to choose as these point to the pages of your webapp where the user should be redirected to after a successful login or logout.

Replace YourClientId & YourClientSecret with the value provided to you by our Support.

Verify user is logged in

The UserManager provides a getUser function to know if the user is logged into the JavaScript application.
It uses a JavaScript Promise to return the results asynchronously.
The returned User object has a profile property which contains the claims for the user.

Add this code to detect if the user is logged into the JavaScript application:

mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
    }
    else {
        log("User not logged in");
    }
});

Implement functions

Next, we want to implement the login, api, and logout functions.
The UserManager provides a signinRedirect to log the user in, and a signoutRedirect to log the user out.
The User object that we obtained in the above code also has an access_token property which can be used to authenticate to a web API.
The access_token will be passed to the web API via the Authorization header with the Bearer scheme.

Add this code to implement those three functions in your application:

function login() {
    mgr.signinRedirect();
}

function api() {
    mgr.getUser().then(function (user) {
        var url = "https://securedapi/test";

        var xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onload = function () {
            log(xhr.status, JSON.parse(xhr.responseText));
        }
        xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
        xhr.send();
    });
}

function logout() {
    mgr.signoutRedirect();
}

Callback

This page is the designated redirect_uri page once the user has logged into NxtPort. It will complete the OpenID protocol sign-in handshake with NxtPort.
The code for this is all provided by the UserManager class we used earlier. Once the sign-in is complete, we can then redirect the user back to the main index.html page.

Add this code to complete the sign-in process in the <body> of the <html> code of your login screens:

 

<script src="oidc-client.js"></script> 
<script> new Oidc.UserManager({response_mode:"query"}).signinRedirectCallback().then(function() {
window.location = "index.html"; }).catch(function(e) { console.error(e); }); </script>

 

For more information, please take a look at the official documentation page of IdentityServer: http://docs.identityserver.io/en/latest/quickstarts/4_javascript_client.html


Step 5 – When the system detects a user is not logged in, the user will be auto-redirect to our login page


Step 6 – After a successful login, the user will be auto-redirect to the redirect uri that was provided in the initial request

If the login failed, the user will stay on our login page to retry the login


Step 7 – Use the access token for all requests to the NxtPort Platform

Include the access token in the header Authorization: Bearer [access token goes here]

Include the API key in the header Ocp-Apim-Subscription-Key: [API key goes here]

The API key can be found in the subscription detail view of the asset you're subscribed to (see step 0).

 

Login with your own login screen

Creating your own login screen in your software to use for a NxtPort login is not allowed due to security reasons.

 
Register your company