---
title: "identity.subject-assertion-claims@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/identity.subject-assertion-claims"
updated: null
---

# identity.subject-assertion-claims@1 · OpenVibe.Services

HTML: [identity.subject-assertion-claims@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/identity.subject-assertion-claims)

# SubjectAssertionClaims `identity.subject-assertion-claims@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: network
- Visibility: public
- Status: active
- Compatibility: backward
- Decision: [ADR-003](/docs/adr/ADR-003)
- Schema: [`https://openvibe.network/contracts/identity/subject-assertion-claims.v1.json`](/docs/contracts/identity.subject-assertion-claims.json)

Claims of a short-lived ES256 assertion signed by OpenVibe.Network that says a person allowed one service to act for them on another service (ADR-003, amendment 2026-11-06; plan H1). Minted only from the person's own Network access token (POST /internal/subject-assertions): without that token nothing is signed. Carried on a money call in X-OV-Subject-Assertion. The signature key is published in Network's JWKS (kid ov-network-assertion-1, kty EC, alg ES256) beside the RS256 session key, so a receiver verifies it offline.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `iss` | string | yes | Issuer; https://openvibe.network in production. The receiver checks it against the issuer it expects. | - `format uri` |
| `sub` | string | yes | The person the assertion is about: their canonical subject. The receiver refuses an assertion that does not name the person the route acts for. | - `pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$` |
| `aud` | array of string | yes | The service(s) the assertion is for. A receiver accepts it only when its own audience is in the list. A list is used when the assertion travels a chain (a tip goes from the site to Tips and on to Billing). | - `minItems 1`<br>- `items: pattern ^openvibe\.[a-z0-9][a-z0-9.-]*$` |
| `act` | string | yes | The service the assertion was minted for (the one that held the person's token). It is the only service that may present it, unless \`for\` names others. | - `pattern ^svc:[a-z][a-z0-9-]{1,39}$` |
| `for` | array of string |  | The services that may carry the assertion (the minting service is always in it). A receiver presented by a service that is not in this list refuses the assertion (403 assertion.actor\_mismatch). | - `items: pattern ^svc:[a-z][a-z0-9-]{1,39}$` |
| `jti` | string | yes | Unique per assertion. A receiver remembers the jtis it has seen for the replay window and refuses a second use (403 assertion.replayed). | - `minLength 8` |
| `iat` | integer | yes | Issued at (seconds since the epoch). |  |
| `exp` | integer | yes | Expires at (seconds since the epoch). The assertion lives 60 seconds. |  |
| `nbf` | integer |  | Not before (seconds since the epoch). Optional; a receiver forgives a small clock difference. |  |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: chain-tip-to-billing

~~~~
{
  "iss": "https://openvibe.network",
  "sub": "usr_01JAB2C3D4E5F6G7H8J9K0MNA1",
  "aud": [
    "openvibe.tips",
    "openvibe.billing"
  ],
  "act": "svc:live",
  "for": [
    "svc:live",
    "svc:tips"
  ],
  "jti": "as_abcdef13",
  "iat": 1790000000,
  "exp": 1790000060
}
~~~~

Valid: live-to-billing

~~~~
{
  "iss": "https://openvibe.network",
  "sub": "usr_01JAB2C3D4E5F6G7H8J9K0MNA1",
  "aud": [
    "openvibe.billing"
  ],
  "act": "svc:live",
  "jti": "as_abcdef12",
  "iat": 1790000000,
  "exp": 1790000060
}
~~~~

Rejected: no-jti

~~~~
{
  "iss": "https://openvibe.network",
  "sub": "usr_01JAB2C3D4E5F6G7H8J9K0MNA1",
  "aud": [
    "openvibe.billing"
  ],
  "act": "svc:live",
  "iat": 1790000000,
  "exp": 1790000060
}
~~~~

Rejected: no-person

~~~~
{
  "iss": "https://openvibe.network",
  "sub": "svc:live",
  "aud": [
    "openvibe.billing"
  ],
  "act": "svc:live",
  "jti": "as_abcdef12",
  "iat": 1790000000,
  "exp": 1790000060
}
~~~~

Rejected: other-audience

~~~~
{
  "iss": "https://openvibe.network",
  "sub": "usr_01JAB2C3D4E5F6G7H8J9K0MNA1",
  "aud": [
    "media"
  ],
  "act": "svc:live",
  "jti": "as_abcdef12",
  "iat": 1790000000,
  "exp": 1790000060
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('identity.subject-assertion-claims@1', value);   // { valid, errors: [{ path, message }] }
~~~~
