NetworkConsentClaim network.consent-claim@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- network
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/network/consent-claim.v1.json
network.consent-claim@1 (the consent plan's C4, 2026-11-07): the purposes a person granted to one app at sign-in, as the `consent` claim of the tokens OpenVibe.Network issues to that app. An app asks with one scope `consent:<purpose>` per purpose, beside its other scopes, in /oauth/authorize. The purposes an app may ask for are network.consent@1's except the retired ai.looks: ai.train, data.public, face.recognize and app.data. Any other `consent:` scope is refused with invalid_scope. The consent screen lists each purpose in plain words, off until the person ticks it, and the person can sign in with every purpose refused. A granted purpose is a network.consent@1 record with the app's OAuth client id as client and source oauth; the person turns it off on their account page (DELETE /api/v1/me/consent/:purpose/:client). A refused purpose is not asked again by that app for 30 days, unless the person asks for it again on their account page. The schema is the claims object of any token that carries the claim: a first-party user access token, a Dock token, or an app token (identity.service-token-claims@1).
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
consent | array of enum | yes | Exactly the purposes this sign-in asked for that the person has granted to this app and that are active when the token is issued, in network.consent@1's order. Never a refused or unasked purpose and never another app's grant. An empty list means none is granted: the app learns "not granted", never whether the person refused or was not asked. The claim is absent when the sign-in asked for no consent scope. Every new token works it out again, so a purpose the person turns off is gone from the next one (a refresh, or the next code); a token already issued keeps it until it expires. A service about to use a person's content for an app still asks POST /internal/consent/check with the app as client. The token response's `scope` lists consent:<purpose> only for the purposes granted. |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: app-token-all-four
{
"iss": "https://openvibe.network",
"sub": "app:app_01K6R3A1B2C3D4E5F6G7H8J9KD",
"actor_type": "app",
"aud": [
"openvibe.media"
],
"cap": [],
"ns": [
"prj_01J0000000000000000000000Z",
"app.prj_01J0000000000000000000000Z.*"
],
"iat": 1790000000,
"exp": 1790000300,
"jti": "tok_abcdef21",
"project_id": "prj_01J0000000000000000000000Z",
"env": "production",
"on_behalf_of": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"consent": [
"ai.train",
"data.public",
"face.recognize",
"app.data"
]
}Valid: app-token-none-granted
{
"iss": "https://openvibe.network",
"sub": "app:app_01K6R3A1B2C3D4E5F6G7H8J9KD",
"actor_type": "app",
"aud": [
"openvibe.media"
],
"cap": [],
"ns": [
"prj_01J0000000000000000000000Z",
"app.prj_01J0000000000000000000000Z.*"
],
"iat": 1790000000,
"exp": 1790000300,
"jti": "tok_abcdef21",
"project_id": "prj_01J0000000000000000000000Z",
"env": "production",
"on_behalf_of": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"consent": []
}Valid: user-token-one-granted
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"consent": [
"ai.train"
],
"iat": 1790000000,
"exp": 1790003600
}Rejected: duplicate
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"consent": [
"ai.train",
"ai.train"
],
"iat": 1790000000,
"exp": 1790003600
}Rejected: missing-claim
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"iat": 1790000000,
"exp": 1790003600
}Rejected: not-a-list
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"consent": "ai.train",
"iat": 1790000000,
"exp": 1790003600
}Rejected: retired-purpose
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"consent": [
"ai.looks"
],
"iat": 1790000000,
"exp": 1790003600
}Rejected: unknown-purpose
{
"sub": "42",
"id": "42",
"subject_id": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"username": "ana",
"client_id": "openvibe-live",
"consent": [
"data.sell"
],
"iat": 1790000000,
"exp": 1790003600
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('network.consent-claim@1', value); // { valid, errors: [{ path, message }] }