NexJ Logo

Model Server OAuth support

OAuth 2.0 support is provided by the OAuth 2.0 authenticator component, which is implemented by nexj.core.rpc.http.OAuthenticationInterceptor in the rpc mixin.

This authentication interceptor implements outbound (client; HTTPClient.Authenticator interface) and inbound (server; AuthenticationInterceptor interface) authentication protocols based on the OAuth 2 specifications as used by many providers, including the Microsoft Identity Platform (also known as Azure Active Directory or AAD), as well as optional client SSL certificate authentication as an inbound alternative.

As a design goal, it has been implemented to support the AAD protocols that are useful for NexJ applications, and ensure that the implementation is compatible with other relevant OAuth 2 authentication providers.

These single sign-on protocols are similar to Kerberos 5 and NexJ perimeter authentication, and are described in several RFC documents. The main idea is delegating the authentication to a dedicated trusted service, which can be reused by multiple applications with the same end-user credentials. The login UI, where relevant, is typically also delegated, so that the credential checks (for example, various implementations of multi-factor authentication) can evolve without modifying the applications using the authentication service.

The application to which the client ID (also known as the application ID) belongs must be registered with the authentication service provider in a vendor-specific way.

AAD registration

The admin UI is currently at https://aad.portal.azure.com.

Azure Active Directory/Application Registrations:

  • Authentication: choose single tenant or multi tenant, depending on the use case; with multi tenant, users from any AAD organization can authenticate with the application

  • Certificates & secrets: add a client secret (also known as password) and record the value as it will vanish (for example, MySecret expires in 3/19/2022 value - abcdef1~BOW4AUK8kRRp--J7.zg3JR5hX and ID - abcdef1-a01b-4d96-ad43-6a6248eb8dbd)

For outbound protocols, set the user property of the HTTPConnection to the client/application ID and the password property to the client secret.

For inbound protocols, override the applicationId and applicationPassword properties of the relevant provider component (System.OAuth.AAD.comp).

Certificate authentication

Alternatively, set up the more secure certificate authentication.

  1. Generate a public or private key pair in PKCS 12 format:

    keytool -genkeypair -dname CN=AppName -validity 3650 -keyalg RSA -keysize 4096 -alias appname \ 
    -storetype pkcs12 -keystore appname-aad.pfx -storepass HardtoGuess.0356
  2. Convert the public key to a base64 certificate:

    keytool -export -rfc -alias appname -storetype pkcs12 -keystore appname-aad.pfx \ 
    -storepass HardtoGuess.0356 -file appname-aad.cer
  3. Add the converted appname-aad.cer certificate to Azure Active Directory/Application Registrations/Certificates & Secrets (and delete the client secrets, so they could not be used instead).

  4. Convert the PKCS 12 key store to base64 format:

    base64 -w0 appname-aad.pfx >appname-aad.b64
  5. For outbound protocols, copy the base64 content to the certificate property of the HTTPConnection and set the password property to the key store password. The user property is still the client/application ID. For inbound protocols, override the applicationId, applicationCertificate and applicationPassword properties of the relevant provider component (System.OAuth.AAD.comp).

    URL redirects have to be configured for the inbound protocols only.

General information

The outbound protocols are invoked using #authenticate(HTTPClient, Value), which references several configuration properties affecting the authentication. If the user name specified in the HTTP client password provider contains ':', it is treated as a user:clientId concatenation, the password is also split the same way, and the resource owner password credentials (ROPC) grant (https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc; RFC 6749, 4.3) is used, notably for accessing Exchange Online mail boxes with the EWS API, otherwise the client credentials grant (https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow; RFC 6749, 4.4) is used.

The inbound protocols are invoked using #authenticate(ServletContext, HttpServletRequest, HttpServletResponse, InvocationContext).

The authorization code grant (https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow; RFC 6749, 4.1) and the OpenID Connect (https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc; https://openid.net/specs/openid-connect-core-1_0.html) are supported, with an option for the authenticated user to self-enroll or apply for enrollment into the accessed application.

The access token returned by AAD is invalid (it cannot be validated with the provider keys), therefore the ID token is used for authorization instead, which is allowed in confidential clients (with a secret, the use case implemented by this interceptor). Reverting to the access token is a matter of changing several lines of code, while continuing to use the ID token for the OpenID connect protocol.

The authentication (ID/access) token has the same purpose as the NexJ perimeter authentication token and is stored along with other relevant tokens in corresponding HTTP cookies. The token is confidential and must not be passed to untrusted code or entities. It is validated on every intercepted request and for speeding this up a token to principal cache with an expiry timeout is maintained.

The token validation in #createPrincipal(String) consists of constraint checks, most notably client/application ID, time range and digital signature verification.

The provider-specific cryptographic keys are retrieved, cached and maintained in the corresponding OAuthProvider singleton component instances.

Multiple providers are supported simultaneously and the resulting authenticated principal name is prefixed with the provider name (for example, keycloak:User1). A UI endpoint can receive the $auth=provider-name URL parameter to specify the authentication provider, otherwise the first valid provider in the provider collection, per OAuthProvider#isValid(), is used. RPC endpoints do not reply with an HTTP redirect (the provider login form if the JWT token is invalid or missing).

The JWT token and the OAuth 2 principal are set in the security context upon successful authentication.

It has two "providers" and a third that should be added which are implemented in nexj.core.rpc.http.OAuthProvider from the rpc mixin.

OAuthProvider has the following properties:

  • name = The name of the component.
  • id = unique identifier that is encountered in the issues URL. It is for detecting the provider from a token issuer URL.
  • applicationCertificate = Sets the application client certificate. The base64-encoded key store. If used, then the applicationPassword is the keystore password otherwise applicationPassword is the "client_secret."
  • applicationId = Sets the application's "client_id."
  • applicationPassword = Sets the application's "client_secret" or the keystore password for the applicationCertificate if set.
  • authorizationURL = Sets the Authorization Server's authorization URL. It usually ends in "authorize". Supports ${rootURL}, ${tenant}, and ${host} expansion. 

  • certificateURL = Sets the Authorization Server's certificate URI. It usually ends in "certs". Supports ${rootURL}, ${tenant}, and ${host} expansion. 

  • certificateHashAlgorithm = Sets the certificate hash algorithm name: "x5t" for "SHA-1" or "x5t#S256" for "SHA-256"
  • host = Sets the logical element used to replace ${host} in rootURL, authorizationURL, tokenURL, and certificateURL.
  • individualId = Sets the Individual Tenant ID.
  • metadata = Advanced.
  • minCertificateRefreshPeriod = Sets the minimal certificate refresh period in milliseconds.
  • rootURL = Sets the logical element used to replace ${rootURL} (expanded first with tenant and host replacements) in the authorizationURL, tokenURL, and certificateURL.
  • signatureAlgorithm = Sets the JWT signature algorithm to "RS256" or "RS384" or"RS512."
  • tenant = Sets the logical element used to replace ${tenant} in the various "URL" values.
  • timeTolerance = Sets the time skew tolerance in milliseconds.
  • tokenURL = Sets the Authorization Server's authorization URL. It usually ends in "token or access-token." Supports ${rootURL}, ${tenant}, and ${host} expansion. FUTURE: lookup based on the Authorization Server's metadata URL.

And the following providers are configured with the following property overrides:

rpc:System.OAuth.AAD

  • name=AAD

  • aad.id=abcdef1-6c67-4c5b-b112-36a304b66dad

  • aad.tenant=

  • aad.host=login.microsoftonline.com

  • aad.authorizationURL=https://${host}/${tenant}/oauth2/v2.0/authorize

  • aad.tokenURL=https://${host}/${tenant}/oauth2/v2.0/token

  • aad.certificateURL=https://${host}/${tenant}/discovery/v2.0/keys

  • aad.individualId=abcdef1-6c67-4c5b-b112-36a304b66dad

  • aad.certificateHashAlgorithm=x5t

  • aad.signatureAlgorithm">RS256

  • aad.applicationId=

  • aad.applicationCertificate=

  • aad.applicationPassword=

  • metadata=


rpc:System.OAuth.Keycloak

  • name=Keycloak

  • keycloak.tenant=

  • keycloak.host=

  • keycloak.rootURL=https://${host}/auth/realms

  • keycloak.authorizationURL=${rootURL}/${tenant}/protocol/openid-connect/auth

  • keycloak.tokenURL=${rootURL}/${tenant}/protocol/openid-connect/token

  • keycloak.certificateURL=${rootURL}/${tenant}/protocol/openid-connect/certs

  • keycloak.applicationId=


rpc:System.OAuth.Generic

  • name=Generic

  • oauth.rootURL=https://${host}/auth/realms

  • oauth.authorizationURL=${rootURL}/v1/authentication

  • oauth.tokenURL=${rootURL}/v1/token

  • oauth.certificateURL=${rootURL}/v1/certs

  • oauth.applicationId=


This documentation has been extracted from the rpc mixin mainly from JavaDoc in nexj.core.rpc.http.OAuthenticationInterceptor and was up to date with that content as of March 19, 2021.