Skip to main content

Trust Subject Flow

Policy constraints often need to know something about the other party: its role, its country, a certification it holds. Nothing on the provider node can look those facts up, so they travel with the negotiation. The consumer publishes them as the subject of its trust token, the provider verifies the token and keeps the subject on the agreement as trustData, and every later evaluation of that agreement sees them under $.subject in the information data source. This page follows that path component by component, states what the verification does and does not prove, and records the design decisions behind it.

The Path​

Trust Subject Flow: from the consumer's information sources to a constraint

Consumer node
A public information source entry holds the attributes to disclose, for example a role and a country.
Provider node
Holds the offer and, later, the agreement that carries the verified attributes.
1. PNP gathers the subject
The negotiation point calls the information point with no policy and the public access mode, and hands the result to the trust component as the credential subject.
2. PNP verifies the token
Expiry, signature, revocation, issuer and subject are checked. The credential subject is kept on the negotiation and offered to the negotiator.
Signed verifiable credential
Issued by the consumer organisation identity, it travels with the contract request message.
3. PAP stores trustData
At finalisation the agreement is created with the verified credential and its subject as trustData, beside the rules.
4. Enforcement on the provider
The enforcement point forwards the agreement's trustData to the decision point, which spreads it over the information point output. Constraints read the attributes as $.subject.role from the information data source and the arbiter grants or denies.
  1. The consumer publishes facts. A consumer node exposes the attributes it is willing to disclose through an information source in public access mode. With the built-in sources that means a static entry such as { "accessMode": "public", "objects": { "role": "BorderAgency", "country": "GB" } }; the identity sources contribute nothing at this point (see Information Sources).
  2. The consumer PNP gathers them. When the consumer starts a negotiation, PolicyNegotiationPointService calls the information point with no policy and the public mode, retrieve(undefined, "public"), and passes the result to the trust component as the subject: generate(organizationIdentity, overrideType, { subject }).
  3. The trust component issues the token. The JWT verifiable credential generator creates a credential whose credentialSubject is that object, issued by the consumer's organisation identity and signed with its verification method, with an optional expiry. An empty subject is replaced by { "id": "<organisation identity>" }. The token travels with the contract request message to the provider.
  4. The provider PNP verifies. requestFromConsumer hands the token to TrustHelper.verifyTrust. The JWT verifier rejects an expired token, verifies the credential through the identity component (a bad signature is rejected there and a revoked credential is reported), and requires an issuer and a credential subject. It returns the issuer as the counterparty identity together with two data objects: verifiableCredential, the whole verified credential, and subject, its credential subject. The PNP keeps that result on the negotiation as trustVerificationInfo and passes the data to the negotiator's handleOffer as additional information for its decision. Every later message in the negotiation is verified the same way and must come from the same identity.
  5. The PAP persists it. At finalisation the PNP creates the agreement in the administration point with trustData: trustVerificationInfo.data, and the PAP stores it on the policy entity beside the rules (IRightsManagementPolicyTrust). It is returned with the agreement on every later getAgreement.
  6. Enforcement forwards it. At access time the caller hands the agreement to the enforcement point. interceptWithId and interceptWithLocator load the agreement from the PAP and forward its trustData themselves; interceptWithPolicy takes trustData as its fourth parameter, and the dataspace data plane passes agreement.trustData there for both pull and push enforcement.
  7. The PDP merges. PolicyDecisionPointService.evaluate calls the information point with the agreement and the any mode, then spreads the trust data over the result: { ...information, ...trustData }. The keys verifiableCredential and subject therefore override anything an information source returned under the same names, and the merged object is what every arbiter receives as information.
  8. The arbiter reads it. A constraint addresses the verified attributes with the information data source and a path under subject:
{
"leftOperand": "twin:jsonPath",
"twin:jsonPathDataSource": "information",
"twin:jsonPathExpression": "$.subject.role",
"operator": "eq",
"rightOperand": "BorderAgency"
}

The same condition can scope a rule to a party instead, as a PartyCollection refinement on the rule's assignee; the Default Policy Arbiter page describes both forms. Use case 8 walks the whole path with fixtures for the granted and the denied outcome.

The Subject at Each Hop​

HopShape
Consumer static source entry{ "role": "BorderAgency", "country": "GB" }
Credential subject in the token{ "role": "BorderAgency", "country": "GB" }
trustData on the provider's agreement{ "verifiableCredential": { "..." : "" }, "subject": { "role": "BorderAgency", "country": "GB" } }
information seen by the arbiterThe information source output plus the two keys above
Constraint path$.subject.role with "twin:jsonPathDataSource": "information"

Note the nesting: sources publish top-level keys and the verifier introduces the subject level. A source configured with { "subject": { "role": "BorderAgency" } } would end up at $.subject.subject.role.

Security Caveat​

The subject is self-asserted. The consumer node puts whatever its public information sources return into the credential, and verification proves only that the token was issued by the identity it names, is signed with that identity's key, has not expired and has not been revoked. It does not prove that the consumer is a border agency, only that the consumer said so under its own signature. A constraint on $.subject.<attribute> is therefore a check on the counterparty's declaration, adequate for routing and self-classification, and not a substitute for an attestation. Facts that must be established independently belong in a provider-side information source (a profile, a catalogue, a registry lookup) or in a credential issued by a third party that a custom source or verifier checks.

The trust data is also captured once. The subject reflects what the consumer published when the negotiation started; a later change on the consumer node does not update existing agreements.

Design Decisions​

  • Information sources serve facts that are local or global to the node. A source answers from its own node's configuration, identity documents, profiles or other reachable data. It receives the policy, the payload and the action, and at enforcement time the policy it receives is the stored agreement complete with trustData, so a custom source could read the counterparty's subject from the agreement if a design called for it. Whether it does so is a design choice for that source; no plumbing is missing.
  • Attributes about the other party travel in the trust payload. The counterparty's attributes are disclosed by the counterparty, verified as its signed statement, and frozen on the agreement. This keeps the provider's evaluation independent of the consumer's availability at access time and gives a single, auditable record of what was claimed when the agreement was formed.
  • The negotiation-time retrieve is deliberately policy-less and public. At that moment no policy exists on the consumer side, and the answer is disclosed to another organisation, so only sources that can answer without a policy, and only entries marked public or any, contribute. The identity and profile sources stay silent by construction.
  • The stored trust data is the counterparty's. Each node persists the verified data of the other party: the provider's copy of the agreement carries the consumer's subject, and the consumer's copy carries what the provider's negotiation tokens declared. A node never stores its own subject on its own agreement. Consumer-side enforcement of $.subject.* constraints, which would need the consumer's own subject, is tracked as consumer-side trust subject capture.
  • Facts are node-global. The static source is one shared instance, so attributes added to it at request time (for example a calling user's roles) leak into every negotiation the node starts and can race under concurrency. A per-request channel for subject attributes is the subject of a spike on per-request trust payload subjects; until it lands, the subject should carry attributes of the organisation, not of an individual caller.