Rights Management
This document defines the architecture of the TWIN Foundation Rights Management subsystem. It specifies the responsibility boundaries of core components, the policy and negotiation lifecycle, extensibility contracts, and interaction flows (including integration with IDS Contract Negotiation and ODRL policy semantics). The intent is to precise describe the runtime model so that new extensions can be implemented without ambiguity.
A majority of the modules form part of the specification International Data Spaces Architecture Model - Policy Enforcement
Core domain concepts:
Implemented architectural components:
- Policy Administration Point (PAP)
- Policy Management Point (PMP)
- Policy Information Point (PIP)
- Policy Execution Point (PXP)
- Policy Decision Point (PDP)
- Policy Enforcement Point (PEP)
- Policy Negotiation Point (PNP)
- Policy Negotiation Admin Point (PNAP)
Concepts
Policy
Policies are encoded using the ODRL information model. A Policy instance may be an Offer (provider-side promise) or an Agreement (mutual contract). Policies are treated as immutable once persisted except via explicit administrative update operations in the PAP (e.g. revocation, supersession). Integrity, provenance, and version traceability are expected but outside the immediate scope of this document.
Policy Locator
A Policy Locator is a structured selector used to reduce the candidate policy search space for execution or negotiation. It MUST contain sufficient discriminators such that the set returned by the PMP is computationally tractable.
Typical discriminator fields:
| Field | Meaning |
|---|---|
assetType | Logical asset class or domain aggregate identifier. |
action | Requested operation (e.g. read, write, invoke). |
assignee | (Optional) Target principal (consumer identity) relevant to Agreements. |
Wildcard semantics: a wildcard for a field does NOT match all stored values; it only matches policies for which that field value is absent / undefined. This enables inheritance‑style fallbacks while avoiding uncontrolled broad scans.
Offer
An Offer is a Policy containing a mandatory assigner (provider identity) and no mandatory assignee. It represents a unilateral capability that MAY be negotiated into an Agreement. Offer invariants: (1) assigner MUST be resolvable to a DID or equivalent verified identity; (2) constraints/duties MAY be present; (3) obligations MUST be satisfiable by the prospective consumer.
Agreement
An Agreement is a Policy containing both mandatory assigner and assignee. It is the authoritative contract artifact produced by negotiation or administrative issuance. Agreements MAY embed constraints, duties (obligations), and prohibitions consistent with ODRL. Post‑finalisation mutation SHOULD be limited to status transitions (e.g. revocation) recorded with audit metadata.
Node
A Node is an independently deployable TWIN runtime instance that can both publish Offers and acquire Agreements for remote data assets. Each Node exposes a DID document containing a verification method named (by convention) node-authentication-assertion used for cross-node authorization tokens.
Authorization
Cross-node invocations are authenticated using a detached trust mechanism rather than local user credentials. Each rights management HTTP interface requires an Authorization header of the form:
Authorization: Bearer <jwt>
The JWT MUST be signed with the private key corresponding to the caller Node's DID verification method node-authentication-assertion.
Verification steps:
- Resolve caller DID document.
- Extract
node-authentication-assertionpublic key material. - Verify signature and standard claims (iat/exp/nbf) plus domain-specific claims (e.g. requesting node id, audience).
- Reject if expired, malformed, unsupported algorithm, or key mismatch.
Policy Administration Point (PAP)
The PAP provides authoritative persistence for Policy entities.
Capabilities:
- Create / update / soft delete (revocation) / read by identifier.
- Query by indexed fields aligned with Policy Locator discriminators.
- Enforce structural validation against the ODRL model subset adopted by the platform.
The PAP MUST NOT implement evaluation semantics; it is intentionally passive.
Policy Management Point (PMP)
The PMP resolves candidate Policies relevant to an access evaluation or negotiation request.
Responsibilities:
- Translate a Policy Locator into one or more PAP queries (including wildcard = missing field logic).
- Apply in-memory filtering for secondary criteria not indexed in storage.
- Return an ordered set (deterministic, typically by specificity then recency) to the PDP or PNP.
The PMP MUST avoid returning duplicate logical policies (e.g. multiple versions) unless explicitly requested.
Policy Information Point (PIP)
The PIP supplies contextual facts (JSON-LD documents) to evaluators and negotiators. Extensibility is achieved via registered Information Sources.
Invocation model:
- PDP request: ALL sources invoked (parallel where possible); both private and public facts returned.
- PNP negotiation: ONLY public facts exposed to counterparties; private facts retained for local decision support.
Sources SHOULD be side-effect free and SHOULD implement internal caching for expensive lookups.
Policy Execution Point (PXP)
The PXP provides ordered pre-/post-evaluation interception around PDP decision computation. Extension units are Execution Actions.
Lifecycle:
beforephase: actions receive locator, candidate policies, and preliminary context (no decisions yet). They MAY enrich context or short-circuit (e.g. deny all) subject to platform policy.afterphase: actions receive immutable decision set; they MAY emit telemetry, obligations scheduling requests, or enforcement hints.
Actions MUST be idempotent and SHOULD be resilient to partial failure (one failing action must not corrupt the evaluation pipeline unless configured as critical).
Policy Decision Point (PDP)
The PDP produces an authoritative authorization decision set (permits / denials / obligations) for a given Policy Locator and input data context. It composes PMP, PIP, PXP, and registered Arbiters.
Evaluation pipeline:
- Resolve candidate policies via PMP.
- Invoke PXP
beforeactions. - Aggregate contextual facts via PIP.
- Invoke each Arbiter with (policies, context facts, request data). Arbiters return zero or more atomic decisions.
- Normalize and merge decisions (deduplicate, resolve conflicts via Arbiter-defined precedence or platform defaults).
- Invoke PXP
afteractions. - Return final decision set to caller (PEP or other consumer).
Error handling: If zero Arbiters are registered an error (e.g. noSupportedArbiters) MUST be raised. Individual Arbiter failures SHOULD be isolated; a catastrophic failure aborts with decidingFailed (exact codes defined elsewhere).
Arbiters SHOULD be deterministic for identical inputs and MUST NOT mutate shared policy objects.
Party Scoping (PartyCollection Refinements)
A rule's assigner/assignee may be a plain party id, a Party object with a uid, or an ODRL PartyCollection scoping the rule to parties matching a refinement (e.g. "applies to any assignee whose verified role is BorderAgency") instead of a fixed id. This is the ODRL-idiomatic way to express attribute-scoped rules, and the default Arbiter supports it as follows:
- A
PartyCollectionwith nosourcebut with arefinement: the collection contributes no party id, so the rule's applicability to that party is decided entirely by evaluating itsrefinementconstraints against the same datasources (data,information) used for rule-level constraints — including verified counterparty attributes carried ininformationvia the negotiated Agreement'strustData. A rule with both a resolvable id and a refinement-only collection (a compact-form array) is expanded into independent alternative rules per ODRL's compact-form semantics — each is evaluated on its own, not ANDed together. - A party entry that resolves to neither a party id nor a refinement (e.g. a
PartyCollectionwith nosourceand norefinement, or a malformed/untyped party object the Arbiter can't otherwise classify) is not treated as "no constraint, applies to anyone." It falls back to the ordinary id-matching path, which denies on an empty id list — the same fail-closed behavior as before this scoping mechanism existed. Only a genuine, non-emptyrefinementunlocks the attribute-matching path above. - A
PartyCollectionwith asource(member ids resolved from an external source at decision time) is not supported and the Arbiter throwspartyCollectionSourceNotSupported. This is a deliberate, permanent limitation, not a gap pending a future fix — resolving collection membership from an external source at decision time is a materially larger capability (network lookups inside the Arbiter) that no current deployment requires. - This applies identically to permissions, prohibitions, and obligations, and to both
assignerandassignee.
Asset Scoping (AssetCollection Refinements)
A rule's target may be a plain asset id, an Asset object, or an ODRL AssetCollection scoping the rule to a set of member assets instead of a single fixed one. The default Arbiter supports it as follows, mirroring the PartyCollection pattern above where noted:
- An
AssetCollectionwithsource: "twin:jsonPath": the collection'stwin:jsonPathExpressionis resolved as a wildcard path (typically ending in[*]) over the data source, and arefinement(if present) is applied per-member, expanding to independent per-item decisions. This is the original, longer-standing mechanism (used by, e.g.,docs/use-cases/02-country-filtered-consignments). - An
AssetCollectionwith nosourcebut with arefinement: the collection contributes no wildcard expansion — the target resolves to"$"(the whole decision payload), and therefinementis applied as an ordinary rule-level constraint against the same datasources used for other rule constraints, mirroring how a source-lessPartyCollectioncontributes refinements without ids. This is not a per-item mechanism; there is no array to iterate without atwin:jsonPathsource, soshouldExpandToPerItemTargets()never triggers for this shape. - An
AssetCollectionwith neithersourcenorrefinement: also resolves to"$". Unlike the equivalentPartyCollectioncase above, which stays fail-closed and denies on an empty id list, this is treated the same as an entirely absent target and grants — there is no id-matching concept for assets the way there is for parties, so "no scoping information at all" has no fail-closed fallback to fall back to. - An
AssetCollectionwith any other definedsourcevalue (neither absent nor"twin:jsonPath") is not supported and the Arbiter throwsassetCollectionSourceNotSupported. This mirrorsPartyCollection's treatment of an unsupportedsource— the Arbiter only recognizes"twin:jsonPath"as a resolvable external-source form. - This applies identically to permissions, prohibitions, and obligations.
Policy Enforcement Point (PEP)
The PEP applies PDP decisions to a candidate data set.
Process:
- Submit locator + data to PDP.
- Receive decision set (permits, denies, obligations, transformations hints).
- Execute registered
Enforcement Processorssequentially, each producing the next data version. - Return the final (potentially redacted or transformed) data or raise an enforcement exception.
Ordering is deterministic by registration sequence.
Applying Enforcement
Any in-process component can invoke policy enforcement directly by resolving the PEP component and calling intercept().
This provides:
- Inline authorization (permit / deny) for a single piece of JSON-LD data or collection.
- Declarative transformation (redaction, augmentation, obligation-driven adjustments) applied consistently with the rest of the platform.
Illustrative usage:
// No input data, just trying to see if data is accessible
// the return type is determined by the PEP
const response = await pep.intercept({
locator: { assetType: 'aig:AuditableItemGraphVertex', action: 'use' }
});
const isAllowed = Coerce.boolean(response);
console.log('Access is allowed', isAllowed);
// JSON-LD document from regular data processing is handed
// to the PEP to transform the data
const processedAigDocument = await pep.intercept({
locator: { assetType: 'aig:AuditableItemGraphVertex', action: 'read' },
data: aigDocument
});
Embedding the PEP directly inside component‑specific REST endpoints constrains cross‑node interoperability: authorization remains bound to the nodes internal credential domain, preventing external nodes from invoking those endpoints via standardized rights‑management tokens.
Policy Negotiation Point (PNP)
The PNP implements the IDS Contract Negotiation state machine, producing Agreements from Offers through bilateral interaction.
Capabilities:
- Register Offers for one or more asset classes / data types.
- Initiate or accept negotiations; persist state transitions atomically.
- Select a
Negotiator(producer side) by probing for support; reuse selected negotiator for the negotiation lifespan. - Dispatch negotiation progress events to a
Requester(consumer side callback handler). - Finalize: on
FINALIZED, persist Agreement into PAP. - Termination handling with explicit reason codes.
Extensibility:
- Negotiators implement Offer evaluation, counter-offer generation, and potential obligation insertion.
- Requesters receive lifecycle callbacks: offer, agreement, finalised, terminated (names normative).
Manual Intervention
A Negotiator MAY request a pause requiring administrative action. Such negotiations enter a managed state handled through PNAP operations before resumption.
Direct Agreement (REQUESTED → AGREED Shortcut)
The IDS Contract Negotiation state machine permits a Provider-initiated REQUESTED → AGREED transition as a first-class alternative to the full REQUESTED → OFFERED → ACCEPTED → AGREED cycle — both are explicit transitions in the canonical state machine, not one being an approximation of the other.
A Negotiator opts a negotiation into this shortcut by setting directAgreement: true on the result of handleOffer(), alongside accepted. When set (and interventionRequired is not also set — that always takes precedence, since a shortcut must never bypass a required manual review), the PNP skips scheduling the Offer message and instead builds and sends the Agreement directly. VERIFIED and FINALIZED proceed identically to the full cycle regardless of which path produced AGREED.
Upgrade order (breaking change)
A negotiation only reaches AGREED directly if the consumer's deployed rights-management-pnp-service accepts an inbound ContractAgreementMessage while its local negotiation is still REQUESTED (not only ACCEPTED, which is all older versions accept). A Provider whose Negotiator signals directAgreement: true while talking to a Consumer running an older version will see that negotiation fail: the Consumer rejects the message and its own record is silently abandoned in REQUESTED (recovered only by PNAP's cleanup sweep), while the Provider's record is separately marked TERMINATED.
Because PassThroughPolicyNegotiator now defaults to directAgreement: true, upgrade every Consumer-side deployment before any Provider-side deployment that uses PassThroughPolicyNegotiator picks up this version. If providers and consumers cannot be upgraded together, pass { directAgreement: false } on the Provider side until every Consumer it negotiates with is confirmed upgraded.
Policy Negotiation Admin Point (PNAP)
PNAP exposes administrative CRUD + query over negotiation instances.
Functions:
- Query stalled / intervention-required negotiations.
- Apply administrative decisions (approve, reject, inject amended terms).
- Resume or terminate negotiations with auditable rationale.
Extensibility Patterns
| Extension | Interface | Register Via | Notes |
|---|---|---|---|
| Arbiter | IPolicyArbiter | registerArbiter (PDP) | Multiple arbiters aggregated; conflict resolution strategy documented per deployment. |
| Negotiator | IPolicyNegotiator | registerNegotiator (PNP) | First supporting negotiator selected (ordered probing). |
| Requester | IPolicyRequester | registerRequester (PNP) | Receives lifecycle callbacks (offer, agreement, finalised, terminated). |
| Information Source | IPolicyInformationSource | registerSource (PIP) | Provides contextual facts (public/private partition). |
| Enforcement Processor | IPolicyEnforcementProcessor | registerProcessor (PEP) | Sequential data transformation; ordering deterministic. |
| Execution Action | IPolicyExecutionAction | registerAction (PXP) | Pre-/post-evaluation interception. |
All extension points MUST be able to be safely unregistered (idempotent) and SHOULD validate uniqueness where duplicate registration would cause ambiguity.