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:
- An
entity
part (representing a responsible stable entity) . - An
access
part (for access control).
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
andexp
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".