ServiceTokenClaims identity.service-token-claims@1

Generated at from openvibe-contracts v0.114.0 and openvibe-sdk v0.35.1.

Version
1.3.0
Owner
network
Visibility
public
Status
active
Compatibility
backward
Decision
ADR-003
Schema
https://openvibe.network/contracts/identity/service-token-claims.v1.json

Claims of a short-lived RS256 client-credentials token issued by OpenVibe.Network to a service, app, mod, node or agent principal. Replaces X-Internal-Key. App tokens (actor_type app) also carry project_id and env; receivers refuse env=sandbox unless they opted in. Agent tokens (actor_type agent, sub agent:agt_<ULID>) are minted for the agent's host and also carry project_id, env and on_behalf_of (the owner), and optionally cap_confirm and act.

Fields

FieldTypeRequiredDescriptionConstraints
issstringyesIssuer; https://openvibe.network in production. Receivers pass the issuer they expect to verifyServiceToken().
  • format uri
substringyes
  • pattern ^(svc:[a-z][a-z0-9-]{1,39}|app:app_[0-9A-HJKMNP-TV-Z]{26}|mod:mod_[0-9A-HJKMNP-TV-Z]{26}|node:nod_[0-9A-HJKMNP-TV-Z]{26}|agent:agt_[0-9A-HJKMNP-TV-Z]{26})$
actor_typeenumyes
  • one of "service", "app", "mod", "node", "agent"
audarray of stringyes
  • minItems 1
  • items: pattern ^[a-z0-9.-]+$
caparray of stringyesGranted capability ids; a trailing .* grants a family.
  • items: pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_*]+)+$
cap_confirmarray of stringAgent tokens: capabilities the agent holds in confirm mode. Each use needs an approved network.confirmation-request@1, presented as OpenVibe-Confirmation: cnf_<ULID> and consumed by the owning service. Never also in cap, so a receiver that does not know agents refuses those actions.
  • items: pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$
nsarray of stringNamespace constraints, e.g. live.* or mod.example.*. A developer app token carries its project_id (the whole project, as issued before namespaces were rows) and app.<project_id>.*: on Media, app.<project_id> and app.<project_id>.sandbox are the project's production and sandbox namespaces, with children below them.
iatintegeryes
expintegeryes
jtistringyes
  • minLength 8
project_idstringDeveloper project of an app or agent principal (ADR-014). Services key tenancy by it. Absent on first-party service tokens.
  • pattern ^prj_[0-9A-HJKMNP-TV-Z]{26}$
envenumEnvironment of an app or agent principal. A receiver MUST refuse env=sandbox (401 token.sandbox_refused) unless it opted in to sandbox tokens. Absent on first-party service tokens, which are production.
  • one of "sandbox", "production"
on_behalf_ofstringThe person who authorized an app through the authorization-code flow, or the owner an agent acts for (always present on agent tokens). Absent on client_credentials tokens.
  • pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$
actobjectAgent tokens: the host that runs the agent and the token was minted for (RFC 8693 actor claim), a service or an app.
  • no other fields
act.substringyes
  • pattern ^(svc:[a-z][a-z0-9-]{1,39}|app:app_[0-9A-HJKMNP-TV-Z]{26})$

Examples

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

Valid: agent-app-host-auto-only
{
  "iss": "https://openvibe.network",
  "sub": "agent:agt_01J0000000000000000000000Z",
  "actor_type": "agent",
  "aud": [
    "openvibe.media"
  ],
  "cap": [
    "media.object.read"
  ],
  "ns": [
    "prj_01J0000000000000000000000Z",
    "app.prj_01J0000000000000000000000Z.*"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent002",
  "project_id": "prj_01J0000000000000000000000Z",
  "env": "sandbox",
  "on_behalf_of": "usr_01J0000000000000000000000Z",
  "act": {
    "sub": "app:app_01J0000000000000000000000Z"
  }
}
Valid: agent-service-host
{
  "iss": "https://openvibe.network",
  "sub": "agent:agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "agent",
  "aud": [
    "openvibe.chat"
  ],
  "cap": [
    "chat.presence.read"
  ],
  "cap_confirm": [
    "chat.message.send"
  ],
  "ns": [
    "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent001",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "on_behalf_of": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "act": {
    "sub": "svc:actor"
  }
}
Valid: app-project-namespaces
{
  "iss": "https://openvibe.network",
  "sub": "app:app_01J0000000000000000000000Z",
  "actor_type": "app",
  "aud": [
    "openvibe.media"
  ],
  "cap": [
    "media.object.upload",
    "media.object.read",
    "media.object.list",
    "media.object.delete"
  ],
  "ns": [
    "prj_01J0000000000000000000000Z",
    "app.prj_01J0000000000000000000000Z.*"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_abcdef13",
  "project_id": "prj_01J0000000000000000000000Z",
  "env": "production"
}
Valid: app-sandbox
{
  "iss": "https://openvibe.network",
  "sub": "app:app_01J0000000000000000000000Z",
  "actor_type": "app",
  "aud": [
    "openvibe.media"
  ],
  "cap": [
    "media.object.upload",
    "media.object.read"
  ],
  "ns": [
    "live.*"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_abcdef12",
  "project_id": "prj_01J0000000000000000000000Z",
  "env": "sandbox",
  "on_behalf_of": "usr_01J0000000000000000000000Z"
}
Valid: live-to-media
{
  "iss": "https://openvibe.network",
  "sub": "svc:live",
  "actor_type": "service",
  "aud": [
    "openvibe.media"
  ],
  "cap": [
    "media.object.upload",
    "media.object.read"
  ],
  "ns": [
    "live.*"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_abcdef12"
}
Valid: node-token
{
  "iss": "https://openvibe.network",
  "sub": "node:nod_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "node",
  "aud": [
    "openvibe.bot"
  ],
  "cap": [
    "network.node.self.manage"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_node0001"
}
Rejected: agent-actor-with-service-sub
{
  "iss": "https://openvibe.network",
  "sub": "svc:actor",
  "actor_type": "agent",
  "aud": [
    "openvibe.chat"
  ],
  "cap": [
    "chat.presence.read"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent005",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "on_behalf_of": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
}
Rejected: agent-bad-actor-claim
{
  "iss": "https://openvibe.network",
  "sub": "agent:agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "agent",
  "aud": [
    "openvibe.chat"
  ],
  "cap": [
    "chat.presence.read"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent006",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "on_behalf_of": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "act": {
    "sub": "agent:agt_01J0000000000000000000000Z"
  }
}
Rejected: agent-sub-as-service
{
  "iss": "https://openvibe.network",
  "sub": "agent:agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "service",
  "aud": [
    "openvibe.chat"
  ],
  "cap": [
    "chat.message.send"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent004"
}
Rejected: agent-without-owner
{
  "iss": "https://openvibe.network",
  "sub": "agent:agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "agent",
  "aud": [
    "openvibe.chat"
  ],
  "cap": [],
  "cap_confirm": [
    "chat.message.send"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_agent003",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "act": {
    "sub": "svc:actor"
  }
}
Rejected: app-without-project
{
  "iss": "https://openvibe.network",
  "sub": "app:app_01J0000000000000000000000Z",
  "actor_type": "app",
  "aud": [
    "openvibe.media"
  ],
  "cap": [
    "media.object.upload",
    "media.object.read"
  ],
  "ns": [
    "live.*"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_abcdef12",
  "env": "sandbox",
  "on_behalf_of": "usr_01J0000000000000000000000Z"
}
Rejected: no-audience
{
  "iss": "https://openvibe.network",
  "sub": "svc:live",
  "actor_type": "service",
  "aud": [],
  "cap": [],
  "iat": 1,
  "exp": 2,
  "jti": "tok_abcdef12"
}
Rejected: node-bad-id
{
  "iss": "https://openvibe.network",
  "sub": "node:nod_42",
  "actor_type": "node",
  "aud": [
    "openvibe.bot"
  ],
  "cap": [
    "network.node.self.manage"
  ],
  "iat": 1790000000,
  "exp": 1790000300,
  "jti": "tok_node0001"
}
Rejected: non-uri-issuer
{
  "iss": "openvibe network",
  "sub": "svc:live",
  "actor_type": "service",
  "aud": [
    "openvibe.media"
  ],
  "cap": [],
  "iat": 1,
  "exp": 2,
  "jti": "tok_abcdef12"
}
Rejected: user-subject
{
  "iss": "https://openvibe.network",
  "sub": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "actor_type": "service",
  "aud": [
    "openvibe.media"
  ],
  "cap": [],
  "iat": 1,
  "exp": 2,
  "jti": "tok_abcdef12"
}

Validate

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