PermDock
Standards

OpenAPI registries

The OpenAPI Initiative registries, the x-permdock- namespace PermDock emits, which registered x-oai-* extensions it reuses, why it does not use x-agent-trust, the JWS typ values and media types PermDock signs with, and the rule for never inventing names in someone else's namespace.

Status: planned

What it is

The OpenAPI Initiative maintains a set of registries that give shared names to things the specification itself leaves open:

RegistryWhat it lists
Extension FieldIndividual x-* fields with a defined meaning and the objects they may appear on
NamespacePrefixes of the form x-{namespace}- reserved for one organisation or project
FormatValues for the JSON Schema format keyword
Tag KindValues for the tag kind field
Media TypeMedia types with defined handling in OpenAPI descriptions
Draft FeatureFeatures being trialled before they enter the specification
Alternative SchemaSchema languages other than JSON Schema that a description may reference

Registering is a pull request against OAI/spec.openapis.org that adds a Markdown file under registries/_{registryName}. The Namespace Registry requires the prefix format x-{namespace}- with lowercase identifiers; registered namespaces are fdx, jsonschema, ms, oai (reserved for the OpenAPI Initiative), oas-draft, oas, sap and scalar.

The Extension Registry entries that matter to PermDock:

  • x-oai-deprecated: marks a Security Scheme deprecated in documents older than 3.2.
  • x-oai-deviceAuthorization: the OAuth 2.0 device authorization flow inside flows, pre-3.2.
  • x-oai-deviceAuthorizationUrl: the RFC 8628 device authorization endpoint, pre-3.2.
  • x-agent-trust: a trust-level block (algorithm, trustLevels, issuerKeysUrl) for apiKey schemes whose header is Agent-Signature, from the draft-sharif-agent-identity-framework family. It is listed here because it looks close to Web Bot Auth and is not: PermDock does not emit it (see below).

There is no registered x-oai-oauth2MetadataUrl, and permdock is not a registered namespace today.

Why it matters for PermDock

PermDock puts permission keys, portable conditions, approval metadata and security-profile declarations into OpenAPI documents so gateways, SDK generators, portals and agents can read them. Every one of those fields is an extension. Two things go wrong when extensions are named casually:

  • Collisions. An x-permissions field means something different to every tool that emits one. A registered namespace makes x-permdock-permissions mean exactly one thing.
  • Impersonation. Writing an unregistered x-oai-* name looks official and is not; a viewer that implements the registered x-oai-* set will ignore it or, worse, misread it. oai is reserved for the OpenAPI Initiative.

Conversely, when a registered extension already says what PermDock needs to say, reusing it means other tools understand the output without knowing PermDock exists. That is why the 3.1 fallbacks for device authorization and deprecation use the x-oai-* names. The converse also holds: a registered name whose definition is for a different protocol is not reused because it looks close, which is why the Web Bot Auth scheme carries no x-agent-trust.

How PermDock uses it

The permdock namespace

Registering permdock in the Namespace Registry is planned; the permdock/openapi entry and permdock openapi already emit the prefix. The registration is:

  1. Open a pull request against OAI/spec.openapis.org adding a Markdown file for the permdock namespace under the namespace registry directory.
  2. Prefix: x-permdock-; identifiers are lowercase, camelCase after the prefix as in x-permdock-securityProfile (the registry constrains the namespace token, not the suffix).
  3. Point the entry at this page as the description of every field in the namespace.

Until the registration lands, the extensions are still valid OpenAPI (any x- field is), but the prefix is not reserved. Nothing in PermDock's output changes when it is.

PermDock extensions

ExtensionAppears onJSON shapePurpose
x-permdock-permissionsOperationArray of permission keys: ["post.delete"]; the matching scope of each key appears in the operation's securityThe permissions protect enforces on the route, in catalog terms
x-permdock-conditionsOperationObject keyed by permission key whose values are portable condition JSON (wire formats)What a scope allows beyond "the scope is present", e.g. authorId = principal.id
x-permdock-securityProfileSecurity Scheme, OperationString, currently "fapi2"Declares that the resource server implements a named security profile (FAPI 2.0); an operation-level value overrides the scheme's. On --target 3.3 output it is the stable twin of the native type: profile scheme and securityProfileRequirements emitted from the pinned OpenAPI 3.3 draft, so consumers that ignore the draft still see the declaration
x-permdock-approvalOperationObject keyed by permission key: { "post.delete": { "reason": "human" } }The operation may answer approval-required; clients can plan for an approval step (approvals)
x-permdock-arityOperation (permdock openapi emit --arity only){ "kind": "collection" } or { "kind": "instance", "parameter": "id" }Whether the operation acts on one resource and which path parameter carries its id, for generated MCP servers and SDKs (permdock openapi)
x-permdock-oauth2MetadataUrlSecurity Scheme (3.1 targets only)URL stringFallback for the 3.2 oauth2MetadataUrl field, for which no x-oai-* extension is registered
x-permdock-catalogRoot{ "v": 1, "generator": "permdock/openapi", "drafts": { "oas": "3.3-dev@<commit>", "securityProfiles": "oai-discussion-5304@2026-09-01", "overlay": "1.2-dev@<commit>" } }Identifies the generator and the shape version (v); it carries no catalog hash, because permdock openapi --check detects drift by regenerating the output and comparing it. drafts is present only when the output depends on an unfinished specification (today: --target 3.3 for oas and securityProfiles, --overlay 1.2 for overlay) and names each pinned revision; --check fails and permdock doctor warns when the pins differ from the installed CLI's

Every value is plain JSON that survives the same round trips as a permission leaf; nothing in an extension is a reference to a runtime object.

x-permdock-permissions needs only the permission references, so permissionsExtension(permissions) and securityFor(permission) in permdock/openapi build it without a policy, for contract packages that cannot import server code (contract packages). The other operation extensions read the grants and come from the policy-backed emitter.

{
  "paths": {
    "/posts/{id}": {
      "delete": {
        "operationId": "deletePost",
        "security": [{ "permdockOAuth": ["post:delete"] }],
        "x-permdock-permissions": ["post.delete"],
        "x-permdock-conditions": {
          "post.delete": {
            "op": "eq",
            "field": "authorId",
            "value": { "ref": "principal.id" }
          }
        },
        "x-permdock-approval": { "post.delete": { "reason": "human" } },
        "x-permdock-securityProfile": "fapi2",
        "responses": {
          "204": { "description": "Deleted" },
          "403": { "$ref": "#/components/responses/PermDockDenied" }
        }
      }
    }
  }
}

Registered names PermDock reuses

SituationRegistered extensionWhere PermDock writes it
Deprecated scheme, --target 3.1x-oai-deprecatedSecurity Scheme
Device authorization flow, --target 3.1x-oai-deviceAuthorizationInside flows of an oauth2 scheme
Device authorization endpoint, --target 3.1x-oai-deviceAuthorizationUrlInside that flow

JWS typ values PermDock emits

These are not OpenAPI extensions but they are the other namespace PermDock writes into a registered-vocabulary position: the typ header parameter of every JWS PermDock signs (RFC 7515 section 4.1.9; the value is a media type name without the application/ prefix per RFC 7519 section 5.1). They are listed here so that one page holds every name PermDock places in a shared registry-shaped slot, and so that emitting a typ not in this table is a documentation failure before it is a code one (JOSE, wire formats).

typPrivate claimEmitted by
permdock-snapshot+jwtsnapshot (snapshot v: 1)permdock.snapshot({ signer }), permdock/cloud snapshots
permdock-approval+jwtapprovalapprovalsHandler({ signer })
permdock-decisions+jwteventsA DecisionSink with signer, permdock/cloud export
permdock-policy+jwtpolicy (policy document v: 1); iss = aud = the Cloud environment URL, exp = iat + 24 hoursPermDock Cloud hosted grants, read by cloud().policies
permdock-capability+jwtcapability (capability v: 1); sub = the link id, exp = capability.expiresAtsignCapability, read by subjectFromCapability

The +jwt structured syntax suffix is registered (RFC 8417 section 7.2), so any JOSE library treats these as JWTs. Each typ is the short form of a media type, and the full names are the media types PermDock documents:

Media typetypCarried as
application/permdock-snapshot+jwtpermdock-snapshot+jwtA signed snapshot in a response body or SnapshotSource payload
application/permdock-approval+jwtpermdock-approval+jwtA signed approval request handed to a delivery surface
application/permdock-decisions+jwtpermdock-decisions+jwtA signed event batch: a sink export or a Cloud webhook delivery
application/permdock-policy+jwtpermdock-policy+jwtThe hosted-grants policy document from GET /policy
application/permdock-capability+jwtpermdock-capability+jwtA link capability, usually in a URL query parameter

On the wire PermDock sends and accepts application/jwt as the Content-Type of every one of them, because a receiver checks typ after verifying and application/jwt is registered (RFC 7519 section 10.3.1); the specific names identify the envelope in documentation, in OpenAPI content keys a team writes for its own endpoints, and in the typ check. They are not registered with IANA, unlike at+jwt (RFC 9068), secevent+jwt (RFC 8417) and logout+jwt (Back-Channel Logout); until they are, the names are safe because a verifier only accepts the typ it was configured for. A breaking change to an envelope is a new typ value and a new row, never a changed row. Fixtures in permdock/testing assert the set of typ values the package can emit equals this table.

For Web Bot Auth, a team that wants signed agent traffic in its description declares an apiKey scheme with in: header and name: Signature-Agent, the header through which the verifier discovers the signer's keys, and lists it as an alternative requirement next to the OAuth scheme. It uses standard fields only:

{
  "components": {
    "securitySchemes": {
      "webBotAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Signature-Agent",
        "description": "RFC 9421 HTTP Message Signature (Web Bot Auth); keys are discovered through the Signature-Agent directory."
      }
    }
  }
}

PermDock does not emit this scheme, because whether a route accepts signed agents is the application's deployment decision, and it does not attach x-agent-trust to it: that extension is defined for the Agent-Signature header of a different draft family, with its own trust-level vocabulary, and a consumer that implements it would misread a Web Bot Auth scheme.

Rules

  1. Never invent an x-oai-* name. The oai namespace belongs to the OpenAPI Initiative; if a 3.2 or 3.3 feature has no registered pre-3.2 extension, the fallback is x-permdock-* (as for oauth2MetadataUrl).
  2. Use a registered extension whenever one exists for the purpose, including extensions outside the oai namespace, and only for the purpose its entry defines.
  3. Otherwise use x-permdock-*, document it in the table above, and version its shape through x-permdock-catalog.v.
  4. Never write into another registered namespace (x-ms-, x-sap-, x-scalar-, x-jsonschema-), nor into an unregistered vendor namespace a consumer reads as its own: gateway import fields (x-amazon-apigateway-*, x-google-*, x-kong-*, x-zuplo-*), docs-host and generator fields (x-mint, x-mcp, x-topics, x-fern-*, x-speakeasy-*, x-stainless-*, x-readme), nor another party's extension for a protocol PermDock has not adopted (the community x-gnap; see GNAP). A team that wants one of those derived from PermDock's fields writes its own consumer-side overlay (OpenAPI ecosystem), even when a field there looks close.
  5. The importer reads the native fields, the registered fallbacks and the x-permdock-* set; unknown extensions are preserved untouched, never dropped.
  6. Draft-only native fields (today the type: profile scheme and securityProfileRequirements on --target 3.3, and the Overlay 1.2 components.actions shape on --overlay 1.2) are emitted only behind an experimental flag, always with a stable twin (the x-permdock-* extension, or the 1.1 Overlay form), and with the pinned revision written into x-permdock-catalog.drafts.

tests/standards/openapi-registry.test.ts enforces rules 1, 3 and 4 mechanically: every x- name in the emitter's output, on every target and in both Overlay versions, must be a row of the extension table above or one of the three registered x-oai-* names, and the JWS typ literals in the source must equal the typ table.

Registration checklist

These steps happen outside this repository. Remove the Status: planned line at the top of this page in the pull request that records the first one as merged.

  1. Namespace: open the pull request against OAI/spec.openapis.org that adds registries/_namespace/permdock.md with prefix x-permdock-, a link to this page and the maintainers' contact; record the PR link here.
  2. Extensions: after the namespace merges, nothing further is needed per field; the table above is the description the registry entry links to.
  3. Media types: decide whether to request IANA registration of the five application/permdock-*+jwt types (a specification-required registration under RFC 6838 section 3.1 needs a published document; this page and wire formats are the candidate). Until then the table above is the only definition.

Why

  • No x-agent-trust. The entry's definition, header name and trust-level vocabulary belong to another draft family. Rule 2 exists so other tools understand PermDock's output; reusing a name for a different protocol produces the opposite.
  • application/jwt on the wire. Receivers already route application/jwt, and the typ check after verification is what selects the envelope; a specific Content-Type would add a second place for the two to disagree.

Mapping table

Registry conceptPermDock concept
Namespace permdock, prefix x-permdock-Every PermDock-specific field in a document
Extension x-oai-deprecatedscheme.deprecated adapter option, 3.1 output
Extension x-oai-deviceAuthorization, x-oai-deviceAuthorizationUrlscheme.flows.deviceAuthorization adapter option (--device-flow), 3.1 output
Extension x-agent-trustNot used: it is defined for Agent-Signature, not Web Bot Auth's Signature-Agent
Extension Registry, no entry for oauth2MetadataUrlx-permdock-oauth2MetadataUrl
Format, Tag Kind, Draft Feature, Alternative Schema registriesNot used; PermDock emits standard JSON Schema formats and no draft features
Media Type registry, IANA media typesapplication/permdock-*+jwt, documented above; not registered
(JOSE, not OAI) JWS typ header valuespermdock-snapshot+jwt, permdock-approval+jwt, permdock-decisions+jwt, permdock-policy+jwt, permdock-capability+jwt, the closed list above

Sources

Last updated on

On this page