Skip to main content
Skip table of contents

Implement "Login with NxtPort" in your software

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 and request a subscription for the API you want to use

Check out Data Services Overview to register your company and subscribe to the relevant API. If you want to register on another environment than "production", 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

At the time of writing, a Public client is the default choice when building a Web App.

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

(plus) No risk for code substitution attacks
(plus) Simple implementation
(plus) No static secret required
(plus) 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 substitution 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

(plus) no risk for code substitution attacks
(plus) uses principle known as "detached signature"
(plus) been around for longer so a lot of documentation available
(minus) requires static secret that needs to be hidden on the client
(minus) identity token is transmitted and might leak (personal identifiable) data - possible GDPR issue
(minus) 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 support ticket 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"

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.

At NxtPort, the client-secret is only intended 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:

C#
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:

C#
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)

C#
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:

C#
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:

HTML
<script src="oidc-client.js"></script>

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

JS
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)

JS
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.

Implement functions

Next, we want to implement the login, an api call, 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 from mgr.getUser() 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:

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

function myApiCall() {
    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:

HTML
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <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>
</body>
</html>

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

NxtPort Login

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.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.