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
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 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
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 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:
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:
<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
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.
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:
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:
<!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.