Skip to content

Authorization and authentication

This section explains platform authorization and authentication, which are the platform engine's complement to NPL parties.

Protocol parties

Parties are the ultimate arbiters of how protocol instances and protocol data are used. Every NPL protocol instance requires the binding of party values, a step referred to as 'party assignment'. Assignments are made via the API at protocol instantiation time.

An NPL party assignment consists of two parts:

Each of these parts in itself may consist of several claims.

Below is an example of what a party assignment may look like. For the moment all claims are optional. However, the iss claim in the entity will become mandatory when the multi node engine is involved.

{
  "entity": {
    "iss": ["http://www.noumenadigital.com"],
    "org": ["Noumena Digital AG"]
  },
  "access": {
    "departments": ["it", "management"],
    "roles": ["engineer", "executive"]
  }
}

Example 1: A party assignment.

The entity part can only be changed as a result of explicit NPL modeling, whereas the access part may be changed unilaterally by the controlling entity (via the engine API).

Authentication

Authentication is about confirming that users are who they say they are. The Noumena platform delegates user authentication to identity management solutions outside the platform (such as Keycloak), and requires a valid JSON Web Token (JWT) to accompany platform requests. These JWTs must be valid, signed, and must contain the following claims:

  • An issuer (iss in the JWT specification) - avoids accepting otherwise valid JWT tokens from unknown sources.
  • A user identifier (sub in the JWT specification) - required for the audit trail.
  • An issuance and expiration time (iat and exp in the JWT specification).
  • Any additional claims necessary to meet the requirements of the corresponding party binding.
{
  "iss": "http://www.noumenadigital.com",
  "sub": "12345",
  "exp": 1630497600,
  "iat": 1630490400,
  "org": "Noumena Digital AG",
  "department": ["it"],
  "roles": ["engineer"]
}

Example 2: A JWT token's payload.

The token's user identifier becomes part of the platform engine's audit trail, but is otherwise immaterial to the functioning of the platform (other more human-readable claims should be used for user-specific authorization as shown in example 4 below).

Engine requests are verified for correctness of the entity, and rejected if the token does not match the protocol instance's party assignment entity values. Specifically, this means each of the claims in the party assignment must also be present in the token.

For example 1 above, only a token that contains both a claim iss with value http://www.noumenadigital.com and a claim org with value Noumena Digital AG is accepted. The token in example 2 meets this requirement.

Authorization

Authorization ascertains the actual access rights. As explained above, requests for which the token's entity does not match are always rejected. If the entity in the token matches the party assignment's entity, authorization is decided based on the party assignment's access.

Authorization also uses the claims in the token. Specifically, for each of the claims in the party assignment, there must be a matching claim with the correct value in the token.

The token in example 2 above meets the requirements of the party assignment in example 1, since the department it as well as the role engineer are present. This is not true for the token in example 3 below, where administrator is missing from the party assignment in example 1.

{
  "iss": "http://www.noumenadigital.com",
  "sub": "12345",
  "exp": 1630497600,
  "iat": 1630490400,
  "department": ["it"],
  "roles": ["administrator"]
}

Example 3: Another JWT token's payload.

It is possible to authorize only a specific user through a user-specific claim, such as the preferred_username claim, as demonstrated in example 4.

{
  "entity": {
    "iss": ["http://www.noumenadigital.com"],
    "org": ["Noumena Digital AG"]
  },
  "access": {
    "preferred_username": "Bill"
  }
}

Example 4: A party assignment limiting access to one specific user.

Note that the most basic authorization check uses no additional claims and relies only on very generic claims for its entity. While valid, this is generally not recommended.

{
  "entity": {
    "iss": ["http://www.noumenadigital.com"],
    "org": ["Noumena Digital AG"]
  },
  "access": {}
}

Example 5: Entity-only authorization.

Reserved claims

Some claims defined by the JWT standard do not make sense for controlling party assignments. For example, claims like iat (issued at) will have a different value whenever the JWT is refreshed. To prevent accidental use of these kind of claims, the following claims are actively ignored:

  • acr
  • allowed-origins
  • auth_time
  • azp
  • exp
  • iat
  • nbf
  • jti
  • realm_access
  • resource_access
  • session_state
  • sid
  • sub
  • typ

Claim structure

JWT tokens use the JSON format for serialization so primitive values are supported. When converted to NPL claims object, the contents of a claim are always interpreted as a set of strings values, including the standard JWT reserved claims. Primitives that are not strings will be stringified, and empty claims will be removed.

All array nestings will be flattened, which means that the nesting of arrays does not have any significance and should not convey any information.

Objects will be parsed such that key-value mappings are represented by a =>-separated path, such that claim: { "foo": 2 } maps to a single claim claim=>foo with the value being a set containing "2". Note that this implies that the separator, =>, should never appear in a claim identifier, as that would make { "foo": { "bar": "baz" } } indistinguishable from {"foo=>bar": "baz"}

The claims can be nested to an arbitrary level.

Example

The following entry in a JWT

"foo": {
  "bar": ["a", ["b"], { "x": ["y", "z"] }, "a", { "c": [] }]
}

maps to the following two claims in our system:

  • foo=>bar, containing the set of strings "a" and "b".
  • foo=>bar=>x, containing the set of strings "y" and "z".