Skip to main content

OAuth2

General information​

info

For Microsoft OAuth2 configuration, see Appendix A.

ADITO provides three OAuth2 login types:

  • oauth2-authorizationcodeflow: Use this login type for delegated user access. It is primarily intended for web client logins, where users authenticate with the OAuth2 provider.

  • oauth2-token: Use this login type for access to REST webservices in ADITO. There is no web client login; an external application requests a token directly and passes it to ADITO in the request header. For more information, see the Web Services documentation.

  • oauth2-clientcredentials: This deprecated login type was formerly used for web services. It validates only whether a token can be generated with the configured tenantId, clientId, clientSecret, and scope; it does not verify the tenant. It supports Microsoft providers only.

All login types require a separate Authentication Provider alias. The alias defines where to authenticate and how ADITO obtains the token.

Configure the Authentication Provider alias​

  1. In the project tree, right-click the alias folder and select New.
  2. Enter a descriptive name, such as oauth2-microsoft.
  3. Select the Authentication Provider alias type.

auth_provider_alias Figure: Select the Authentication Provider alias type.

Deploy the changes.

  1. Double-click the system. The new alias is displayed in the Designer editor under Data_alias, _*SYSTEMALIAS, and related aliases.

  2. Right-click the alias and select Create.

  3. Select the alias and enter the authentication information in the property sheet. Obtain these values from the Microsoft Entra administrator who created the application.

Configure the following properties:

  • tenantId: The company ID.
  • clientId: The application ID.
  • clientSecret: The secret created for the application.
  • scope: The requested permissions. The following examples apply only to MICROSOFT; the required scope depends on the use case and target interface.
    • For a client login, use a scope such as https://outlook.office365.com/.default.
    • For web services, use <clientId>/.default.
tip

If you are planning to use OpenId Connect for Access to the web client, use the scope openid. This also ensures, that a signed JWT will be validated during login.

note

When an outgoing REST call uses auth.createConfigForOAuth2WithAlias(), a scope set on the authentication config overrides the scope defined on the alias. If the authentication config does not set a scope, ADITO uses the alias scope as a fallback. If the REST call must not send a scope although the alias defines one, set the scope explicitly to an empty string.

Configure the login list​

Open the relevant login-list entry and configure its properties as follows:

OAuth2 login typeProperty keyValue
AllaliasThe name of the Authentication Provider alias, for example MyAuthAlias.
oauth2-authorizationcodeflow and oauth2-clientcredentialsoauth2 login domain (optional)The domain of the client credentials, for example demo.onmicrosoft.com. If multiple Microsoft accounts are available, this domain is preselected and only matching-domain users can sign in.
oauth2-authorizationcodeflow and oauth2-clientcredentialsoauth2 user template (optional)The user login template for OAuth2 authentication.

For the examples in this document, use a .onmicrosoft.com login address. You can instead use your regular domain.

oauth2-token​

Use oauth2-token primarily for web services. It expects a token in the Authorization header with the Bearer scheme. Its configuration is analogous to oauth2-authorizationcodeflow.

For Microsoft, the flow works as follows:

  • A third-party application generates a Microsoft token with any supported flow.
  • The application sends an HTTP request to ADITO with the token in the HTTP header.
  • ADITO validates the JWT signature.
  • For application tokens, for example from the Client Credentials flow, ADITO checks the JWT tid claim and uses jDitoWebserviceUser.
  • For user tokens, for example from the Password or Authorization Code flow, ADITO checks the JWT upn claim and identifies the user by UPN. The oauth2 user template can also be used when required.

For third-party providers, ADITO executes the Authentication Provider alias's getUsernameFromAccessTokenProcess. The process must identify the user from the JWT or through an API request.

warning

Validate JWT signatures in this process when required. Until a signature is validated, its claims are untrusted user input.

Certificate authentication​

Since ADITO version 2024.1.4, oauth2-token and oauth2-authorizationcodeflow can authenticate with a certificate. This is currently supported for Microsoft only, not custom third-party configurations.

Create or request a certificate, upload it to the Microsoft Entra application, and provide ADITO with the certificate and its key. Add the certificate to the ADITO keystore.

file_browser_jks Figure: Add the certificate to the ADITO keystore.

For cloud systems, download the keystore from the file browser. Then use KeyStore Explorer to add the certificate.

keystore_explorer Figure: Add the certificate with KeyStore Explorer.

When configuring the Authentication Provider alias, set serverAuthMethod to CERTIFICATE. Then configure certificateName, clientId, scope, and tenantId.

certificate_alias_config Figure: Certificate configuration for an Authentication Provider alias.

CUSTOM third-party providers​

Set the provider value to CUSTOM for external OAuth2 providers other than Microsoft.

custom Figure: Custom OAuth2 provider configuration.

Configure clientId, clientSecret, and scope, then configure the following properties:

  • authorizeEndpointUrl: The provider endpoint that authorizes the user. ADITO redirects users to this URL.

  • authorizeEndpointUrlModifierProcess (optional): A process that adjusts authorizeEndpointUrl before ADITO calls the authorization endpoint. Use it to append URL parameters. The process must return a string that starts with &, for example &key=param.

    The process can access every value defined in the login type's login-list entry through its key without spaces.

    Example:

    https://[OAuth2Provider]/oauth2/v1/auth?[SystemGeneratedParameters][ThisProcessGeneratedParameters]

    For Azure, configure the domain hint in the login list. ADITO appends domain_hint=[YOUR_DOMAIN]; otherwise, it forces account selection with prompt=select_account.

  • accessTokenEndpointUrl: The provider endpoint that issues access tokens.

  • accessTokenResponseType: Specifies whether the REST response returns the token in the JSON body or as a URL parameter.

  • getUsernameFromAccessTokenProcess: An authentication process that runs after ADITO receives the access token and before it searches for the ADITO user. The process must return the identifier, such as an ID or name, of a user stored in the Designer. Select an available authentication process from the list; you cannot enter process code in this property.

    The process can validate the token when the OAuth2 provider supplies a validation service or logic. ADITO core validates only validity, clientId, and scope.

getUsernameFromAccessTokenProcess is required. If it is not set, all login attempts fail.

Authentication processes​

Authentication processes convert the token from a custom provider into a login name stored in ADITO. After deployment, all authentication processes are available in the getUsernameFromAccessTokenProcess list of the Authentication Provider alias.

selection Figure: Select an authentication process for getUsernameFromAccessTokenProcess.

To create an authentication process:

  1. In the Projects window, right-click process and select New.
  2. Enter a descriptive name, such as oauth2_asystemconverttokentologinname.
  3. In the process property sheet, select authentication for variants.

variants Figure: Select the authentication process variant.

Authentication processes are displayed as a group in the ADITO Designer.

group Figure: Authentication processes in the ADITO Designer.

The process can access these local variables:

  1. token: The access token as a string.
  2. token_raw: The complete REST response from the third-party API, including the access token, ID token, and refresh token as JSON.

The response format and content differ between third-party providers. Some responses contain the user identifier directly; otherwise, retrieve it from the provider API with the access token.

The following examples show authentication processes for GitHub, Keycloak, PingFederate, and ADFS.

GitHub​

import { auth } from "@aditosoftware/jdito-types";
import { net } from "@aditosoftware/jdito-types";
import { util } from "@aditosoftware/jdito-types";
import { vars } from "@aditosoftware/jdito-types";
import { result } from "@aditosoftware/jdito-types";

var token = vars.get("$local.token");

var authConfig = auth.createConfigForNoAuth();
var restConfig = net.createConfigForRestWebserviceCall()
.actionType(net.GET)
.url("https://api.github.com/user")
.addHeader("Authorization", "token " + token)
.addHeader("Accept", "application/vnd.github+json");

var resultAsBase64 = net.callRestWebservice(restConfig, authConfig);
var resultAsJsonString = util.decodeBase64String(resultAsBase64);
var loginName = JSON.parse(resultAsJsonString).login;
result.string(loginName);

Keycloak​

import { auth } from "@aditosoftware/jdito-types";
import { net } from "@aditosoftware/jdito-types";
import { util } from "@aditosoftware/jdito-types";
import { vars } from "@aditosoftware/jdito-types";
import { result } from "@aditosoftware/jdito-types";

var token = vars.get("$local.token");

var authConfig = auth.createConfigForNoAuth();
var restConfig = net.createConfigForRestWebserviceCall()
.actionType(net.GET)
.url("http://localhost:8090/realms/oauthtest/protocol/openid-connect/userinfo")
.addHeader("Authorization", "Bearer " + token);

var resultAsBase64 = net.callRestWebservice(restConfig, authConfig);
var resultAsJsonString = util.decodeBase64String(resultAsBase64);
var userTitle = JSON.parse(resultAsJsonString).preferred_username;
result.string(userTitle);

PingFederate​

import { auth, logging } from "@aditosoftware/jdito-types";
import { net } from "@aditosoftware/jdito-types";
import { util } from "@aditosoftware/jdito-types";
import { vars } from "@aditosoftware/jdito-types";
import { result } from "@aditosoftware/jdito-types";

var token = vars.get("$local.token");

var authConfig = auth.createConfigForNoAuth();
var restConfig = net.createConfigForRestWebserviceCall()
.actionType(net.GET)
.url("https://????/idp/userinfo.openid")
.addHeader("Authorization", "Bearer " + token);

var resultAsBase64 = net.callRestWebservice(restConfig, authConfig);
var resultAsJsonString = util.decodeBase64String(resultAsBase64);

var loginName = JSON.parse(resultAsJsonString).Username;
result.string(loginName);

ADFS​

import { util } from "@aditosoftware/jdito-types";
import { vars } from "@aditosoftware/jdito-types";
import { result } from "@aditosoftware/jdito-types";

var tokens = JSON.parse(vars.get("$local.token_raw"));

// Parse the ID token JSON.
function parseJwt(token) {
var base64Payload = token.split(".")[1];
var payloadBuffer = util.decodeBase64String(base64Payload);
return JSON.parse(payloadBuffer.toString());
}

// Use the login claim configured in ADFS.
var upn = parseJwt(tokens.id_token).login;

result.string(upn);

Token Validation for Custom Providers​

warning

It is important to validate the token before using it in order to ensure security. Normally, this was supposed to happen in the getUsernameFromAccessTokenProcess as described above. The name of the property didn't give a good enough indication that validation has to be done here. That's why we introduced explicit parameters for the CUSTOM providers.

Property accessTokenValidationMode​

There are three options that have to be applied depending on the custom provider and the configuration of the provider.

NONE: This is the default setting that you will see on your alias. We chose to have this default value to avoid breaking existing systems. It is really important to change this to one of the following values at least in production environments.

JWT: This is to be used when a signed JWT is used as the access token. Here the public key is downloaded automatically from the JWKS endpoint URL and used to validate the tokens. Note that for the openid scope, this will always be done anyway.

PROCESS: If you are receiving opaque access tokens from your authentication provider, you have to validate the tokens by sending them to a predefined endpoint. This might be the userinfo_endpoint or the introspection endpoint, which would be specified in the .well-known endpoint. As those endpoints are optional in OpenID Connect and OAuth2, we can't provide automatic validation for custom providers. Therefore, an additional property, validateAccessTokenProcess, is displayed; it is hidden when validation mode PROCESS is not selected.

note

The process that can be selected here must perform the validation.

The content of those processes will be pretty similar to the getUsernameFromAccessTokenProcess, except the server expects a boolean value as a result.

alias

An example for Gitlab would be like this:

import { auth, logging } from "@aditosoftware/jdito-types";
import { net } from "@aditosoftware/jdito-types";
import { util } from "@aditosoftware/jdito-types";
import { vars } from "@aditosoftware/jdito-types";
import { result } from "@aditosoftware/jdito-types";

var token = vars.get("$local.token");

var authConfig = auth.createConfigForNoAuth();
var restConfig = net.createConfigForRestWebserviceCall()
.actionType(net.GET)
.url("https://gitlab.adito.de/api/v4/user")
.addHeader("Authorization", "Bearer " + token);

var resultAsBase64 = net.callRestWebservice(restConfig, authConfig);
var resultAsJsonString = util.decodeBase64String(resultAsBase64);
var userTitle = JSON.parse(resultAsJsonString).preferred_username;

// here you might have some additional checks on the result of the webservice call

result.boolean(true);

Note that Gitlab is not recommended as an authentication provider for webservice calls.