Bounded Authority Protocol v1 Wire Profile

Copy Markdown View Source

Document status: normative for contract-major 1. Document revision: rev 1. This document is the single normative authority for the v1 wire profile. It is authored to be verifiable in-repo: a machine extraction of its normative tables is frozen and drift-gated, and every requirement statement carries a stable requirement identifier mapped to conformance evidence. It makes no submission claim about any external venue.

A conforming implementation rejects every unlisted member, value, encoding, or extension with a single closed error value. Successful decode or verification is not a trust-selection or authorization decision: verification produces facts, never authority (see (#verification)).

1. Introduction

The Bounded Authority Protocol (BAP) is a provider-neutral, deterministic profile for bounded proof-of-possession authority. A grant binds an issuer's key to a holder's key and to a closed set of permitted operations; a holder's proof binds one request to exactly one grant; a consumption chain and its archived export bind a sequence of commitments to signed boundaries and an authenticated historical-key path. Every artifact is small, closed, and independently verifiable with public keys only.

The profile defines canonical grant, proof, request-binding, consumption-chain, and archive formats; pure verification functions; and an independently executable conformance corpus. It does not grant operational authority by itself: key custody, trusted-key discovery, issuance, revocation state, replay reservation, and every operational decision belong to a stateful authority runtime outside this profile.

2. Terminology

grant: : A closed, issuer-signed capability object binding an issuer key, a holder key thumbprint, temporal validity, and a closed set of permitted operations.

proof: : A closed, holder-signed request-binding object in the DPoP family [RFC9449], binding one HTTP method, target URI, invocation identifier, operation name, request digest, and the grant digest.

facts: : The value-bearing, redacted, non-authorizing results of successful verification. Facts state what was cryptographically checked; they carry explicit not-evaluated markers for trust and authorization and are never execution credentials.

compact value: : The RFC 7515 compact JWS serialization BASE64URL(protected) "." BASE64URL(payload) "." BASE64URL(signature).

tagged algebra: : The profile's abstract JSON data model (see (#datamodel)), which preserves scalar-type distinctions that raw JSON text does not.

contract-major: : The leading integer of the profile version (v1). Successor majors carry complete, closed, parallel profiles.

3. Overview

An issuer mints a grant over a holder's public-key thumbprint and a closed operation set. To act, the holder presents the grant compact value together with a freshly signed proof whose ath claim is the SHA-256 of the exact grant compact bytes and whose request digest covers the server-derived operation and typed arguments. A verifier with the issuer's public key and the expected request context checks every binding and returns redacted facts. Consumption of an authorized request is recorded as a canonical row in a hash chain; boundary anchors sign a range's ends; key transitions authenticate the historical key path; and an anchored export packages header, anchors, transitions, and rows as length-framed bytes with an exact EOF, so an offline verifier can re-derive and check every byte against caller-supplied boundaries and an out-of-band stored-object version.

Every closed set in this profile is exactly that — closed. The rejection of everything unlisted is not a defensive posture but the profile's central safety invariant.

4. Conformance language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. Lowercase forms carry their normal English meaning and impose no requirement.

The closed-rejection rule is the profile's central invariant (REQ1-CORE-reject-unlisted): a conforming implementation rejects every unlisted member, value, encoding, or extension. It is stated once here as the rationale; each per-section closed-set statement below is its own MUST (REQ1-HEADER-closed-set, REQ1-CLAIM-closed-set, ...) and maps to the conformance cells of the surface it governs. Requirement identifiers are stable and their mapping to conformance evidence is published in the requirement map (Appendix C locates the companion artifacts).

5. Suite identity

This profile constitutes the cryptographic suite BAP1-Ed25519-SHA256: EdDSA over Ed25519 [RFC8032] [RFC8037], SHA-256 digests, RFC 8785 canonical bytes [RFC8785], and the BAP1-* domain separators, with the fixed widths listed in the bounds table (#maxima). Every artifact self-declares this identity through its v claim, typ header, alg value, and domain separators. Evolution happens above this profile, never inside it: successor contract-majors carry their own complete closed profiles and suites, while an ADR 0027 sibling application proof profile carries a byte-distinct protected type, API, media type, and corpus and remains rejected by this profile. A proof's contract-major MUST equal its grant's (REQ1-CORE-proof-major-equals-grant), and the closed-rejection rule above is exactly what makes parallel majors and sibling profiles safe — an artifact of any other major, suite, or proof profile fails closed here (REQ1-CORE-cross-major-reject).

6. Normative references

[RFC2119]: Key words for use in RFCs to Indicate Requirement Levels [RFC8174]: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words [RFC8259]: The JavaScript Object Notation (JSON) Data Interchange Format [RFC8785]: JSON Canonicalization Scheme (JCS) [RFC4648]: The Base16, Base32, and Base64 Data Encodings [RFC7515]: JSON Web Signature (JWS) [RFC7519]: JSON Web Token (JWT) [RFC7638]: JSON Web Key (JWK) Thumbprint [RFC8032]: Edwards-Curve Digital Signature Algorithm (EdDSA) [RFC8037]: Algorithm Identifiers for Ed25519 in JOSE [RFC3986]: Uniform Resource Identifier (URI): Generic Syntax [RFC6838]: Media Type Specifications and Registration Procedures [RFC9449]: OAuth 2.0 Demonstrating Proof-of-Possession (DPoP)

These references supply generic encodings. The closed fields, values, digest prefixes, and bounds in the sections below are this profile's choices.

7. Abstract data model {#datamodel}

The profile's data model is a tagged JSON algebra: a closed set of typed values that preserves the distinctions raw JSON text does not (an integer versus an integral float; source member order; duplicate-name rejection before any map conversion).

  • A decoded value is exactly one of: null, boolean, integer, non-integer finite number, string, array of values, or object of (name, value) members.
  • Objects retain source member order and never collapse duplicate names: a duplicate name at any depth is rejected before map conversion (REQ1-JSON-no-duplicate). Input MUST be one complete RFC 8259 value followed only by JSON whitespace (REQ1-JSON-single-value). UTF-8 is mandatory; strings are preserved without Unicode normalization (REQ1-JSON-no-normalization).
  • Before number conversion, the decoder scans raw RFC 8259 number lexemes outside strings, enforces the lexeme byte ceiling of the bounds table, and compares exact decimal magnitude without floating-point rounding (REQ1-JSON-raw-lexeme). Integers and finite floats are bounded symmetrically to -9007199254740991..9007199254740991 (REQ1-JSON-number-bounds).

The typed projection below maps the tagged algebra onto closed JSON for digest construction: each tagged value projects to a two-element array whose first element names the type, so an integer and an integral float never canonicalize identically. JCS orders projected object members.

Grant and proof compact values use the exact RFC 7515 signing input:

ASCII(base64url(protected) || "." || base64url(payload))

No bytes precede or follow it (REQ1-SIGNING-exact-input). Verification uses the exact received segments; correctly signed closed JSON objects may use any member order (REQ1-SIGNING-any-order). Producers emit one deterministic JCS representation (REQ1-SIGNING-deterministic-produce).

The verifier validates the fixed 32-byte public-key and 64-byte signature encodings, completes all bounded parsing and contextual checks, and then delegates Ed25519 verification to the underlying cryptographic backend. A backend rejection or exception returns exactly the profile's closed error value (REQ1-SIGNING-backend-reject).

The request digest is:

base64url(SHA-256("BAP1-REQUEST\0" || JCS([operation, typed(cast_arguments)])))

The prefix is exact ASCII including its final zero byte (REQ1-SIGNING-digest-prefix). typed/1 projects the tagged JSON algebra to the following closed JSON form before JCS:

tagged valueprojected JSON
:null["null"]
{:boolean, value}["boolean", value]
{:integer, value}["integer", value]
{:float, value}["float", value]
{:string, value}["string", value]
{:array, values}["array", [typed(value), ...]]
{:object, members}["object", {member: typed(value), ...}]

JCS orders projected object members. The explicit scalar tags preserve the protocol's semantic distinction between an integer and an integral float even though RFC 8785 emits both numeric payloads with the same JSON number bytes. cast_arguments may be any tagged JSON value. The BAP1-* domain separators below are the suite-identity markers of BAP1-Ed25519-SHA256 (a successor suite binds its own BAP<contract-major>-* separators under its own major). BAP1-CHAIN\0 and BAP1-ARCHIVE\0 remain reserved for the chain and archive constructions of (#chain) and (#archive). The retired BAP1-GRANT\0 and BAP1-PROOF\0 strings are invalid signing prefixes (REQ1-SIGNING-retired-prefixes).

8. JSON decoding and canonical serialization

A conforming decoder produces the tagged algebra of (#datamodel) under the resource limits of (#maxima): raw and decoded sizes precede decoding; structure and scalar limits apply while decoding; all precede cryptography (REQ1-BOUNDS-ordering).

Canonical serialization emits RFC 8785 bytes from the tagged algebra only. String escaping follows RFC 8785 section 3.2.2.2 exactly: the ASCII control range U+0000..U+001F serializes as \b, \t, \n, \f, \r for U+0008/0009/000A/000C/000D respectively and as lowercase \u00XX for every other control code point; every other code point serializes as its UTF-8 encoding unless it is U+005C (\\) or U+0022 (\"). U+007F (DELETE) is outside the control range and is emitted as the raw byte 0x7f. Lone surrogates are rejected.

Number serialization follows RFC 8785 section 3.2.2.3 (the ECMAScript Number::toString operation): a finite float serializes as the shortest decimal text that round-trips under binary64, fixed or scientific by the decimal exponent e of the leading digit — scientific when e < -6 or e >= 21 (lowercase e, mandatory exponent sign), fixed otherwise. 0.0 and -0.0 both serialize as 0. An integer serializes as plain decimal text with no exponent. Non-finite floats are rejected (REQ1-JSON-jcs-exact).

9. Base64url

Segments use only A-Z, a-z, 0-9, -, and _ (REQ1-B64-alphabet). Padding and whitespace are forbidden (REQ1-B64-no-padding). Length modulo four equal to one is invalid (REQ1-B64-length). Decoding succeeds only when unpadded re-encoding reproduces the input exactly, rejecting non-zero unused pad bits and alternate encodings (REQ1-B64-canonical).

10. Protected headers

The protected headers bind the suite BAP1-Ed25519-SHA256 via their alg and typ values. Member order is insignificant and the member sets are exact:

Compact valueMembers
grantalg: "EdDSA", typ: "ba+cap", kid: key_identifier
proofalg: "EdDSA", typ: "dpop+jwt", jwk: public_OKP_JWK

crit, b64, embedded grant keys, unknown algorithms, and every unlisted member are invalid (REQ1-HEADER-closed-set). Grant kid is a case-sensitive 1–128 byte string of ASCII letters, digits, -, ., _, or ~ (REQ1-HEADER-kid-bytes). It is an untrusted hint, not a trust selector (REQ1-HEADER-kid-not-selector).

The proof JWK is exactly {crv: "Ed25519", kty: "OKP", x: canonical_base64url_32_bytes} in any member order (REQ1-HEADER-proof-jwk). Every additional member, including private d, is invalid (REQ1-HEADER-no-private-jwk). Its RFC 7638 thumbprint preimage is exactly:

{"crv":"Ed25519","kty":"OKP","x":"<canonical-x>"}

The thumbprint is unpadded base64url SHA-256 of those UTF-8 bytes (REQ1-HEADER-thumbprint). Verified facts carry the raw 32-byte digest (REQ1-HEADER-digest-width). Issuer-key fingerprinting uses the same construction over the caller's raw 32-byte public key; kid is excluded (REQ1-HEADER-issuer-fingerprint).

11. Claims

All claim objects are closed (REQ1-CLAIM-closed-set). Names and string values are case-sensitive (REQ1-CLAIM-case-sensitive).

Grant claimType
vinteger, exactly 1
iss, jtinon-empty StringOrURI, at most 512 UTF-8 bytes
audone StringOrURI or a nonempty unique array of at most 64
iat, nbf, expintegral NumericDate
cnfexact object {jkt: canonical_base64url_sha256}
operationsnonempty array of at most 64 operation objects

An operation is exactly {name: string, selectors: selector_array}. Names are unique within the grant and contain 1–128 printable ASCII bytes. The ordered selector array has 1–64 members (REQ1-CLAIM-operation-shape).

Proof claimType
vinteger, exactly 1
jtinon-empty StringOrURI, at most 512 UTF-8 bytes
htm1–32 byte case-sensitive RFC 9110 HTTP method token
htunormalized hierarchical HTTPS target URI
iatintegral NumericDate
nonceoptional non-empty string, at most 512 UTF-8 bytes
ba_invlowercase RFC 4122 UUID
ba_op1–128 byte printable ASCII operation name
ath, ba_reqcanonical unpadded base64url SHA-256

Every proof requires every row except nonce; no other claim is accepted (REQ1-CLAIM-proof-required, REQ1-CLAIM-no-extra). ath is SHA-256 over the ASCII bytes of the complete received grant compact value (REQ1-CLAIM-ath). The method accepts ASCII letters, digits, the punctuation bytes ! # $ % & ' * + - . ^ _ | ~, and grave accent (REQ1-CLAIM-htm-bytes). It is compared byte-for-byte and is never case-normalized (REQ1-CLAIM-htm-no-case-normalize).

The grant v claim MUST be exactly the integer 1 (REQ1-CLAIM-v). The proof v claim MUST be exactly the integer 1 (REQ1-CLAIM-proof-v).

12. Selector algebra

Selectors are closed ordered objects with exactly one of three recognized member sets: {kind}, {kind,path,value}, or {kind,path,values} (REQ1-SELECTOR-closed-set). The kind selects how that recognized set is interpreted:

KindRecognized members and interpretation
allAny recognized member set; path, value, and values are inert when present
equalsExactly {kind: "equals", path: path, value: JSON_value}
one-ofExactly {kind: "one_of", path: path, values: non_empty_JSON_array}

An all selector's inert members remain subject to the enclosing bounded JSON decoder but do not need to satisfy the active equals or one_of shapes. No other member combination is recognized.

A path has 1–32 object-member names, each 1–128 UTF-8 bytes. Paths traverse objects only and never index arrays (REQ1-SELECTOR-path-shape). one_of contains at most 256 values (REQ1-SELECTOR-one-of-size).

Selectors are applied conjunctively to the server-derived tagged arguments. all matches any JSON root. equals and one_of require the path to exist (REQ1-SELECTOR-path-required). Semantic identity preserves tagged scalar distinctions, compares arrays positionally, and compares duplicate-free objects recursively as unordered key/value sets (REQ1-SELECTOR-semantic-identity). It never gives source member order meaning or collapses integer and float tags (REQ1-SELECTOR-no-tag-collapse). No selector grants business authorization (REQ1-SELECTOR-not-authorization).

13. URI normalization

Target URIs are bounded ASCII, hierarchical, and HTTPS-only, with a nonempty authority and host and no user information, fragment, or query. Normalization lowercases scheme and host; uppercases percent hex; decodes only percent-encoded unreserved octets; preserves percent-encoded reserved octets as path data; removes complete dot segments; maps an empty path to /; drops port 443; and preserves a valid nondefault port and all other path bytes. It performs no DNS, IDNA, or network work.

The host uses the exact RFC 3986 grammar: reg-name contains only unreserved, sub-delim, or valid percent-encoded octets; IPv4 uses exact dec-octet forms without leading-zero alternatives; and a bracketed IP literal contains a complete IPv6address or IPvFuture. A present port is one or more decimal digits in 1..65535; its canonical form removes leading zeroes and omits 443. Empty ports and malformed IPv4, IPv6, or IPvFuture literals are invalid.

HTTP, another scheme, an authority-less form, malformed percent escapes, ambiguous authority/port syntax, control/non-ASCII bytes, and out-of-range ports are invalid (REQ1-URI-reject-list). Both expected and proof URIs MUST already equal the normal form (REQ1-URI-pre-normalized); the normalizer performs no DNS, IDNA, or network work (REQ1-URI-no-network).

14. Signing and digest inputs

See (#datamodel) for the exact signing input, the request-digest construction, the typed projection, and the BAP1-* domain separators.

15. Consumption chain and anchored export {#chain}

Consumption rows

One row is the closed JCS object:

{"chain_id":"<StringOrURI>","commitment":"<base64url-32>","previous":"<base64url-32>","sequence":1,"v":1}

Its raw hash is SHA-256("BAP1-CHAIN\0" || canonical_row_bytes). Sequence one requires the all-zero predecessor. Verification accepts a nonempty proper list of raw row binaries and an expected-chain context; it requires exact canonical bytes, chain identity, consecutive sequence, predecessor links, row count, first/last sequence, caller predecessor, and caller head.

Boundary anchors

A boundary anchor is standard compact JWS with exact protected header {"alg":"EdDSA","kid":"...","typ":"ba+chain-anchor"} and a closed JCS payload binding protocol version, anchor identity and time, chain identity, sequence, chain hash, and the RFC 7638 fingerprint derived from the raw Ed25519 public key. Sequence zero requires the all-zero hash.

The caller supplies one exact historical public key and expected-anchor context. Verification requires the signed values, key ID, derived fingerprint, Ed25519 signature, and valid_from <= anchored_at < valid_before; an unbounded upper interval is the only open one.

Authenticated key transitions

A transition is standard compact JWS with exact protected type ba+key-transition. Its closed payload binds transition and chain identities, effective time, current fingerprint, next key ID, and next fingerprint. The current key signs it. Current and next public keys/fingerprints must differ, while their key IDs may be equal; the effective time must lie in both historical intervals.

An anchored export advances through the caller-supplied ordered key list positionally. Transition times strictly increase, fingerprints cannot cycle, the start anchor precedes every transition, and the end anchor is at or after the last transition, including exactly at its effective time. Equal start/end times are permitted only for the no-transition same-key case.

Anchored export framing {#archive}

The archive is the exact binary concatenation:

"BAP1-ARCHIVE\0EXPORT\0"
frame(canonical_header)
frame(start_anchor_compact)
frame(each ordered transition_compact)
frame(each canonical row)
frame(end_anchor_compact)
EOF

Every frame is UINT32_BE(nonzero_length) || bytes. The closed header binds chain identity, first/last sequence, row count, transition count, predecessor, head, and version one. Verification scans a bounded nonempty proper flat chunk list incrementally, requires exact EOF, hashes every raw byte, and compares the raw SHA-256 digest in constant time. It also requires exact equality between the observed object-store version and caller-supplied expected version. The version is out-of-band context; it is not embedded in the archive.

The verifier authenticates both anchors and every transition, checks all rows again, and requires the authenticated start/end tuples to equal the caller's chain boundaries. Producer results and facts are not accepted as stored objects or credentials.

The archive-byte ceiling is exactly:

20 + 8,196 + 2 × 8,196 + 256 × 8,196 + 65,536 × 4,100

16. Public verification contract {#verification}

The verification surfaces are: the untrusted key locator; grant and proof signing-input construction; compact assembly; grant and proof decode; grant verification; combined envelope checking; request-digest construction; consumption-entry encoding; chain checking; boundary-anchor and key-transition signing-input construction; anchored-export encoding and verification; and the versioned primitives (canonical serialization, public JWK encode/decode and thumbprints, URI normalization, bounds construction).

Every verification function is a pure function from caller-supplied bytes and caller-supplied trusted inputs and expected context to one of: a value-bearing, redacted facts result, or the single closed error value (REQ1-VERIFY-revalidate revalidates every structured input field at each public boundary). Verification never selects trusted keys, reserves replay, checks live revocation, grants execution, or overrides a host policy. Compact assembly accepts exactly a signing input and a 64-byte signature — never a key, signer, or callback (REQ1-VERIFY-no-signer-callback).

Every function returns {:ok, value} or exactly {:error, :invalid} (REQ1-VERIFY-return-shape).

Decode results carry an explicit verification-not-evaluated marker (REQ1-VERIFY-decode-not-evaluated). Grant and envelope facts carry an explicit authorization-not-evaluated marker (REQ1-VERIFY-grant-not-authorized); chain, anchor, and transition facts carry only the trust marker. Facts are value-bearing and redacted, with fixed redacted rendering and no generic encoder, string, or enumeration protocol (REQ1-VERIFY-facts-redacted, REQ1-VERIFY-facts-not-credentials). No facts result contains arguments, selector values, raw credentials, signatures, JWK containers, or nonces, and no facts result is accepted as credentials.

Grant verification requires exact key ID, signature, issuer, and audience (REQ1-VERIFY-grant-exact); coherent signed times iat < exp and nbf < exp (REQ1-VERIFY-grant-times); and independently:

iat <= evaluation_time + skew
nbf <= evaluation_time + skew
exp > evaluation_time - skew

It does not require iat <= nbf (REQ1-VERIFY-no-iat-nbf-order). Skew is at most 60 seconds and proof maximum age at most 300 seconds (REQ1-VERIFY-time-bounds). Proof time is inclusive:

evaluation_time - proof_max_age - skew <= iat <= evaluation_time + skew

The nonce is absent in not-required mode and present exactly once and equal in required mode (REQ1-VERIFY-nonce-mode). Combined verification re-verifies the raw grant; verifies holder signature and thumbprint; and binds ath, method, URI, invocation, operation, request digest, time, nonce, and every selector (REQ1-VERIFY-envelope-binding).

Chain verification accepts raw canonical row bytes and mandatory caller boundaries (REQ1-CHAIN-raw-rows-bounds). Anchored-export verification accepts only the raw archive chunks, the stored-object version, an ordered historical public-key chain, and complete expected chain/anchor/transition/digest/object-version context (REQ1-EXPORT-input-shape). It scans and hashes the complete archive, requires exact EOF, authenticates both boundaries and every positional transition, and then independently checks every row (REQ1-EXPORT-complete-scan). The stored-object version is exact out-of-band expected context (REQ1-EXPORT-version-exact). Commitment preimages remain opaque and private (REQ1-EXPORT-preimage-private). A self-consistent chain does not certify that no row was deleted: validly signed shortened or relinked artifacts fail only when compared with the original caller boundaries (REQ1-CHAIN-no-deletion-cert). Successful facts state the performed cryptographic checks and always retain the trust-not-evaluated marker (REQ1-CHAIN-facts-not-evaluated); chain, anchor, and transition facts make no authorization field part of their exact public shape (REQ1-CHAIN-facts-shape).

Language bindings, the frozen reference API surface, and the companion artifact locations are informative (Appendix C).

17. Hard maxima {#maxima}

ResourceMaximum
compact input bytes65,536
encoded segment bytes32,768
decoded segment bytes24,576
raw JSON bytes65,536
nesting depth32
members per object64
items per array256
total JSON value nodes4,096
string bytes8,192
object-name bytes128
numeric lexeme bytes64
integer magnitude9,007,199,254,740,991
float magnitude9,007,199,254,740,991
kid bytes128
JCS output bytes65,536
normalized target URI bytes8,192
issuer, audience, or token identifier bytes512
nonce bytes512
HTTP method bytes32
operation name bytes128
audiences per grant64
operations per grant64
selectors per operation64
selector path segments32
values in one_of256
Ed25519 public key / signature bytes32 / 64
SHA-256 digest bytes32
clock skew seconds60
proof maximum age seconds300
canonical consumption row bytes4,096
consumption rows per range65,536
boundary anchor or key-transition compact bytes8,192
anchored-export header bytes8,192
historical key transitions256
anchored-export chunks65,796
anchored-export bytes270,820,384
object-store version bytes512

Callers MAY tighten resource ceilings with a positive integer (REQ1-BOUNDS-tighten-only). The 32-byte public-key and digest widths and 64-byte signature width are the immutable cryptographic constants of the suite BAP1-Ed25519-SHA256 — they are protocol constants, MUST remain exact (REQ1-BOUNDS-fixed-widths), and cannot be tightened or widened (a successor suite carries its own widths under its own contract-major). Unknown, non-integer, zero, negative, widening, or fixed-width-changing limits are invalid (REQ1-BOUNDS-reject-list). Raw and encoded sizes precede decoding; decoded-size projection precedes allocation; structure and scalar limits apply while decoding/emitting; all precede cryptography (REQ1-BOUNDS-ordering).

18. Untrusted key locator

The locator bounds the complete compact input, requires exactly three segments, then bounds, decodes, and validates only the protected grant header (REQ1-LOCATOR-three-segments). The payload and signature stay opaque (REQ1-LOCATOR-opaque-payload). It returns only the key identifier and an explicit trust-not-evaluated marker. It does not select a key, decode claims or signature bytes, verify, evaluate trust, or authorize (REQ1-LOCATOR-not-authority, REQ1-LOCATOR-no-value-leak). Every failure returns the closed error value without input values (REQ1-LOCATOR-no-value-leak).

19. typ values

The typ registry of this profile:

ValueStatusPurpose
ba+capactiveCapability grant (compact JWS)
dpop+jwtactiveHolder proof (RFC 9449)
ba+chain-anchoractiveSigned consumption-chain boundary anchor
ba+key-transitionactiveAuthenticated historical-key transition
ba+cap-delegatedreservedDelegated attenuated grant
ba+suite-attestationreservedCross-suite content-covering countersignature

The closed v1 profile rejects the reserved values today; their activation is a successor contract-major.

20. IANA considerations

IANA is asked to register the following claim names in the JSON Web Token Claims Registry [RFC7519] (Specification Required): ba_inv (invocation UUID), ba_op (operation name), and ba_req (request digest). The names ba_dlg, ba_offline, and ba_sut are reserved by this profile and are NOT registered; no implementation or deployment may use them for anything else before their activating contract-major.

IANA is asked to register the media types application/ba-cap+jwt, application/ba-chain-anchor+jwt, and application/ba-key-transition+jwt (RFC 6838 [RFC6838] field template; LIMITED USE). The names application/ba-cap-delegated+jwt and application/ba-suite-attestation+jwt are reserved for a successor contract-major and are NOT registered. The media-type namespace is distinct from the wire typ header values, which are unchanged by this section.

The ready-to-file registration templates, their machine-readable sources, and the exact reconciliation with the profile's registries document are published with the specification's companion artifacts; the filing itself follows the profile's external submission preconditions.

21. Security considerations

Assets and security goals

The assets are the integrity properties of the wire objects: a grant may only be minted by the issuer's key; a proof only by the holder's key; a request binding only to the exact bytes it names; a consumption chain only to the exact ordered rows and caller boundaries it records; an anchored export only to the complete archived object generation it frames (REQ1-CORE-reject-unlisted). Confidentiality is NOT an asset of this profile: every wire object is plaintext JSON by design; the profile provides authenticity and integrity, and callers transport it over TLS like any other bearer-presented credential.

Adversaries and trust boundaries

The profile assumes the standard Internet threat position for the verifier's inputs: an attacker controls the network path and can read, drop, reorder, or forge every delivered byte. Specific adversaries: (i) a thief of presented credentials lacking the holder's private key; (ii) the legitimate holder attempting request, operation, URI, selector, algorithm, claim, encoding, or time/nonce substitution within an otherwise valid proof; (iii) a malicious or compromised issuer attempting scope widening across grants; (iv) an archive controller supplying a validly signed but shortened, relinked, cross-chain, or wrong-generation history; (v) a contributor weakening the profile itself. The trust boundary is exact: raw credential bytes cross INTO verification; only caller-supplied trusted keys and expected context cross with them; redacted facts and nothing else cross out.

Controls, each mapped to its requirement

Bounded closed parsing precedes all cryptography, defeating allocation amplification and encoding smuggling (REQ1-BOUNDS-ordering, REQ1-CORE-reject-unlisted). Exact-byte constructions — the RFC 7515 signing input, RFC 8785 canonical bytes, the typed projection, and the domain-separated digests — remove ambient-byte and canonicalization-confusion attacks (REQ1-SIGNING-exact-input, REQ1-SIGNING-digest-prefix). Holder possession is proven by the cnf thumbprint and proof-key binding (REQ1-VERIFY-envelope-binding); grant binding by the ath grant digest (REQ1-CLAIM-ath); request binding by the server-derived request digest over [operation, typed(cast_arguments)] (REQ1-CLAIM-ath, REQ1-VERIFY-envelope-binding); temporal validity by bounded signed times with capped skew and proof age (REQ1-VERIFY-time-bounds); freshness by exact nonce mode semantics (REQ1-VERIFY-nonce-mode). Historical key paths advance only through positionally authenticated, strictly time-increasing, cycle-free transitions (REQ1-CORE-cross-major-reject frames the suite identity; the transition controls are the archive-section closed-set requirements), and archive acceptance requires the complete scan, exact EOF, and exact caller boundaries so that validly signed truncations fail (REQ1-EXPORT-complete-scan, REQ1-CHAIN-no-deletion-cert).

Verification is not authority (a security property, not a disclaimer)

A successful verification proves only that caller-supplied bytes satisfy caller-supplied trusted inputs and expected context (REQ1-LOCATOR-not-authority, REQ1-CHAIN-facts-not-evaluated). Trust selection, replay reservation, revocation state, and every operational decision are outside this profile BY DESIGN — an implementation that treats a facts result as execution authority has moved those checks to nothing, which is a security hole in that implementation, not a gap in this profile. Facts are value-bearing, redacted, and carry explicit not-evaluated markers so they cannot silently become credentials (REQ1-VERIFY-facts-not-credentials).

Out of scope, explicitly

Key custody, trusted-key discovery and rotation policy, issuance policy, revocation checking, replay reservation, storage of consumption evidence, witness or recovery processes, denial-of- service mitigation at the deployment boundary, and side-channel hardening of the host platform are outside this profile (the profile's own fixed-width comparisons are constant-time where they compare secrets-adjacent digests). Cryptographic primitive compromise (Ed25519, SHA-256) breaks the corresponding suite entirely; the profile's succession design confines the response to a new contract-major with its own closed suite.

Residual risks

A presented-but-stolen-then-replayed proof inside the skew/proof-age window is indistinguish from fresh use: replay reservation is the runtime's responsibility, and the window bounds (rather than eliminates) exposure. A fully compromised issuer mints valid grants; detection is an operational concern. A conforming verifier that receives correct-but-wrong trusted keys (the wrong issuer key, the wrong expected context) verifies garbage as valid: the profile binds bytes to inputs, not inputs to reality. Archive completeness against a malicious controller requires the caller to retain or derive the intended boundaries (REQ1-CHAIN-no-deletion-cert). Implementation error is a standing residual risk; the conformance corpus and the mutation gates exist to make the common classes loud.

22. Privacy considerations

Correlation surfaces

The profile's identifiers are correlation surfaces. A grant jti is globally unique per grant and observable by every verifier the holder presents to; the proof jti is unique per proof; ba_inv binds a single logical invocation across grant, proof, and the consumption row that records it. Issuer identifiers (iss) and audiences (aud) name services and can cluster holders by the set of issuers they present credentials from. Deployments minimize linkage by scoping identifier allocation per audience where the runtime supports it and by treating the correlation of presentation patterns across verifiers as an accepted property of proof-of-possession credentials of this shape.

Longitudinal evidence in chains and archives

Consumption chains and anchored exports are designed to be durable, verifiable evidence: rows commit to invocation-level digests and are sequentially hash-linked, anchors sign the range ends, and archives freeze complete object generations. The privacy consequence is that retention decisions made by the runtime ARE the privacy posture — the profile makes evidence compact and independently checkable, and it makes deletion detectable (a shortened archive fails the original boundaries), which is a integrity-privacy tension deployments resolve by policy: retention windows, minimization of commitment preimages (which stay opaque and private by construction), and audience-scoped chain identifiers are the available controls.

Nonce handling

Proof nonces are single-use correlation values visible to the verifier that demanded them. They enable per-verifier linkability of otherwise unlinkable presentations. Deployments that require nonces scope them per verifier and rotate them; deployments that do not require them leave the claim absent (its optionality is a privacy feature).

Redacted facts as a privacy control

Verification facts are value-bearing but redacted: they carry identifiers and digests, never cast arguments, selector values, raw credentials, signatures, JWK containers, or nonces (REQ1-VERIFY-facts-redacted). This bounds what a logging or telemetry layer can accumulate from verification outcomes — the loudest privacy control in the profile — and deployments keep it intact by not logging the raw inputs alongside the facts. (informative)

Appendix A. Worked examples (generated from the conformance corpus)

A.1. Accepted examples

A valid grant (decode surface)

Corpus case grant-decode-valid (surface decode_grant, class valid).

  • Compact: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6ImQ0dWNFWnd2SlRmd3hYQ040ZjJ4bUlFNVpCRm9INWk1bWx6ZVdaYUIzeUkifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OjEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiYWxsIn1dfV0sInYiOjF9.NaCpUf3ebKldiRpjHtKcJuvCjSVLSsmgZVWXa3Sz6Zvas3TeTEm3LqVDsUL8yc1VuakYOvFmsYxqQw8PV23uDA
  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A valid holder proof (decode surface)

Corpus case proof-decode-valid (surface decode_proof, class valid).

  • Compact: eyJhbGciOiJFZERTQSIsImp3ayI6eyJjcnYiOiJFZDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6Ilcxczd5RTlmR0RNQmJtZHBxWVZ3UTFoRENYdHpPZVBVRDNmSWYxdDdGRGsifSwidHlwIjoiZHBvcCtqd3QifQ.eyJhdGgiOiJzVjhkZ1ZLcFExTHZpa1lrNmVvOEd2RGZhYkpyMWd0VlhrdkRnazdxLVpZIiwiYmFfaW52IjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIiwiYmFfb3AiOiJyZWFkIiwiYmFfcmVxIjoidXYyMFBpQzh0UlFvT3k5LWVSbEJGUFFuZ3RpRFhrd19TQ2JiZ3p4akMyZyIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUudGVzdC9pbnZva2UiLCJpYXQiOjExMDAsImp0aSI6InVybjpleGFtcGxlOnByb29mOjEiLCJ2IjoxfQ.BUONibEL8cesx2D905h2CwHhL8sdtZ33sABKd7jRl27UdBOo0jpQX9UGl8VLlpEVxSFiZlhBGwNg85VBakhwAw
  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A valid grant (verification surface)

Corpus case verify-grant-valid (surface verify_grant, class valid).

  • Compact: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6ImQ0dWNFWnd2SlRmd3hYQ040ZjJ4bUlFNVpCRm9INWk1bWx6ZVdaYUIzeUkifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OjEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiYWxsIn1dfV0sInYiOjF9.NaCpUf3ebKldiRpjHtKcJuvCjSVLSsmgZVWXa3Sz6Zvas3TeTEm3LqVDsUL8yc1VuakYOvFmsYxqQw8PV23uDA
  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A valid request envelope

Corpus case check-envelope-valid (surface check_envelope, class valid).

  • Grant: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6ImQ0dWNFWnd2SlRmd3hYQ040ZjJ4bUlFNVpCRm9INWk1bWx6ZVdaYUIzeUkifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OjEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiYWxsIn1dfV0sInYiOjF9.NaCpUf3ebKldiRpjHtKcJuvCjSVLSsmgZVWXa3Sz6Zvas3TeTEm3LqVDsUL8yc1VuakYOvFmsYxqQw8PV23uDA
  • Proof: eyJhbGciOiJFZERTQSIsImp3ayI6eyJjcnYiOiJFZDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6Ilcxczd5RTlmR0RNQmJtZHBxWVZ3UTFoRENYdHpPZVBVRDNmSWYxdDdGRGsifSwidHlwIjoiZHBvcCtqd3QifQ.eyJhdGgiOiJzVjhkZ1ZLcFExTHZpa1lrNmVvOEd2RGZhYkpyMWd0VlhrdkRnazdxLVpZIiwiYmFfaW52IjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIiwiYmFfb3AiOiJyZWFkIiwiYmFfcmVxIjoidXYyMFBpQzh0UlFvT3k5LWVSbEJGUFFuZ3RpRFhrd19TQ2JiZ3p4akMyZyIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUudGVzdC9pbnZva2UiLCJpYXQiOjExMDAsImp0aSI6InVybjpleGFtcGxlOnByb29mOjEiLCJ2IjoxfQ.BUONibEL8cesx2D905h2CwHhL8sdtZ33sABKd7jRl27UdBOo0jpQX9UGl8VLlpEVxSFiZlhBGwNg85VBakhwAw
  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A valid consumption chain

Corpus case check-chain-valid (surface check_chain, class valid).

  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A valid anchored export

Corpus case verify-anchored-export-valid (surface verify_anchored_export, class valid).

  • Outcome: accepted — verification succeeds with redacted, non-authorizing facts

A.2. Rejected examples

Rejected: malformed encoding (decode surface)

Corpus case grant-decode-invalid-encoding (surface decode_grant, class invalid_encoding).

  • Compact: bad
  • Outcome: rejected — the single closed error value, no other observable

Rejected: algorithm none

Corpus case grant-decode-invalid-algorithm-none (surface decode_grant, class invalid_algorithm).

  • Compact: eyJhbGciOiJub25lIiwia2lkIjoiaXNzdWVyIiwidHlwIjoiYmErY2FwIn0.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6ImQ0dWNFWnd2SlRmd3hYQ040ZjJ4bUlFNVpCRm9INWk1bWx6ZVdaYUIzeUkifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OjEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiYWxsIn1dfV0sInYiOjF9.NaCpUf3ebKldiRpjHtKcJuvCjSVLSsmgZVWXa3Sz6Zvas3TeTEm3LqVDsUL8yc1VuakYOvFmsYxqQw8PV23uDA
  • Outcome: rejected — the single closed error value, no other observable

Rejected: incoherent signed times

Corpus case decode-grant-invalid-encoding-times-iat-ge-exp (surface decode_grant, class invalid_encoding).

  • Compact: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6IlRySTFnOWhlcjVtek50ZHdUaFV5cXd3R2ZaVkxLZDNNTW9Xa1JZLUZuOGMifSwiZXhwIjoyMDAwLCJpYXQiOjIwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OmZpZWxkcyIsIm5iZiI6MTAwMCwib3BlcmF0aW9ucyI6W3sibmFtZSI6InJlYWQiLCJzZWxlY3RvcnMiOlt7ImtpbmQiOiJhbGwifV19XSwidiI6MX0.tsqChETJ86teYYzsBsHMhg5uxFoCwNdbUhoXWC9Zp8yBddfp8OFPnAxjwDTbgkffuO9nDhdtl5dekbT0m4UWCA
  • Outcome: rejected — the single closed error value, no other observable

Rejected: duplicate audience

Corpus case decode-grant-invalid-encoding-audiences-duplicate (surface decode_grant, class invalid_encoding).

  • Compact: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9hLnRlc3QiLCJodHRwczovL2EudGVzdCJdLCJjbmYiOnsiamt0IjoiVHJJMWc5aGVyNW16TnRkd1RoVXlxd3dHZlpWTEtkM01Nb1drUlktRm44YyJ9LCJleHAiOjIwMDAsImlhdCI6MTAwMCwiaXNzIjoiaHR0cHM6Ly9pc3N1ZXIuZXhhbXBsZS50ZXN0IiwianRpIjoidXJuOmV4YW1wbGU6Z3JhbnQ6ZmllbGRzIiwibmJmIjoxMDAwLCJvcGVyYXRpb25zIjpbeyJuYW1lIjoicmVhZCIsInNlbGVjdG9ycyI6W3sia2luZCI6ImFsbCJ9XX1dLCJ2IjoxfQ.iyY5mBkEqFJyVSsAa0P71OZi1JqeCa17C3tAx7aVafnHBJnPtXsBGzODdd7_DHW9lV8ZrwFRYoTZdV0wgOE0DQ
  • Outcome: rejected — the single closed error value, no other observable

Rejected: holder binding mismatch

Corpus case check-envelope-invalid-claim-holder-binding (surface check_envelope, class invalid_claim).

  • Grant: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6IlRySTFnOWhlcjVtek50ZHdUaFV5cXd3R2ZaVkxLZDNNTW9Xa1JZLUZuOGMifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OmJpbmRpbmctYSIsIm5iZiI6MTAwMCwib3BlcmF0aW9ucyI6W3sibmFtZSI6InJlYWQiLCJzZWxlY3RvcnMiOlt7ImtpbmQiOiJhbGwifV19XSwidiI6MX0.TWfkUWpq2AwChiE35-rrkbyxgXTr8aywpRJAOX2LI7IJ2AcJ7AyBuMIbA5r90Ow8wSdXjIQIXRyJobTGCNr-Dg
  • Proof: eyJhbGciOiJFZERTQSIsImp3ayI6eyJjcnYiOiJFZDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6IlRMV3I5cTE1LV9XcnZNcjh3bW5ZWE5KbEh0UzRoYldHbnlRYTdmQ2x1aWsifSwidHlwIjoiZHBvcCtqd3QifQ.eyJhdGgiOiIwZ3Nqd1QtRHkzZkp1S2xGZXNFYWhjQ3YzNG91eERjcFk3aUZ3cFFhSlV3IiwiYmFfaW52IjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIiwiYmFfb3AiOiJyZWFkIiwiYmFfcmVxIjoidXYyMFBpQzh0UlFvT3k5LWVSbEJGUFFuZ3RpRFhrd19TQ2JiZ3p4akMyZyIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUudGVzdC9pbnZva2UiLCJpYXQiOjExMDAsImp0aSI6InVybjpleGFtcGxlOnByb29mOmJpbmRpbmctd3JvbmctaG9sZGVyIiwidiI6MX0.-6-8UsOBgxTXbprpywP1kyPyhARQMyCgSAMb4iFj_9ZEyfVhxa-7iXNeY2eWeFyl_x_sRLmBmwgtBQt8-CNjCg
  • Outcome: rejected — the single closed error value, no other observable

Rejected: selector-disallowed arguments

Corpus case check-envelope-invalid-selector (surface check_envelope, class invalid_selector).

  • Grant: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6IlRySTFnOWhlcjVtek50ZHdUaFV5cXd3R2ZaVkxLZDNNTW9Xa1JZLUZuOGMifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OnNlbGVjdG9yLTEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiZXF1YWxzIiwicGF0aCI6WyJyZWNvcmQiLCJpZCJdLCJ2YWx1ZSI6InJlYy0xIn1dfV0sInYiOjF9.RhKhp0dsUxk_YOZyRjTJlnkVNVoOJdeW6bFTLDP3Z3IZaTScAVSdC9jvU0kx2EXJi3O2tFLlqBV6uP3kCAfvCQ
  • Proof: eyJhbGciOiJFZERTQSIsImp3ayI6eyJjcnYiOiJFZDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6ImRDSzVpSFdZQm80eXhFU0tsSnJiS1EwUFRqVzU0QnNPNWZHaDVnRC1KblEifSwidHlwIjoiZHBvcCtqd3QifQ.eyJhdGgiOiJldnl3ZGx0Q2FGSDFPVTRaN0M0bGVENGJma3FOVkF2SWlYVmhrWXRTX0RZIiwiYmFfaW52IjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIiwiYmFfb3AiOiJyZWFkIiwiYmFfcmVxIjoiSXVRSXhZOHZ6Ny03MkhjMlQ0b2JBZ0l6Sm5GRk1sQjJDTGlnYmhWZHpDUSIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUudGVzdC9pbnZva2UiLCJpYXQiOjExMDAsImp0aSI6InVybjpleGFtcGxlOnByb29mOnNlbGVjdG9yLXJlamVjdCIsInYiOjF9.QxlsuJEJIw6DUTVxqTIvS8IFMloBHgoCectZ0CSaiq0cRmgHK2HjrVQLvBPipD9IOClS81Lf9nIW6y0Ynl0iBg
  • Outcome: rejected — the single closed error value, no other observable

Rejected: missing required nonce

Corpus case check-envelope-invalid-nonce-required (surface check_envelope, class invalid_nonce).

  • Grant: eyJhbGciOiJFZERTQSIsImtpZCI6Imlzc3VlciIsInR5cCI6ImJhK2NhcCJ9.eyJhdWQiOlsiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLnRlc3QiXSwiY25mIjp7ImprdCI6ImQ0dWNFWnd2SlRmd3hYQ040ZjJ4bUlFNVpCRm9INWk1bWx6ZVdaYUIzeUkifSwiZXhwIjoyMDAwLCJpYXQiOjEwMDAsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUudGVzdCIsImp0aSI6InVybjpleGFtcGxlOmdyYW50OjEiLCJuYmYiOjEwMDAsIm9wZXJhdGlvbnMiOlt7Im5hbWUiOiJyZWFkIiwic2VsZWN0b3JzIjpbeyJraW5kIjoiYWxsIn1dfV0sInYiOjF9.NaCpUf3ebKldiRpjHtKcJuvCjSVLSsmgZVWXa3Sz6Zvas3TeTEm3LqVDsUL8yc1VuakYOvFmsYxqQw8PV23uDA
  • Proof: eyJhbGciOiJFZERTQSIsImp3ayI6eyJjcnYiOiJFZDI1NTE5Iiwia3R5IjoiT0tQIiwieCI6Ilcxczd5RTlmR0RNQmJtZHBxWVZ3UTFoRENYdHpPZVBVRDNmSWYxdDdGRGsifSwidHlwIjoiZHBvcCtqd3QifQ.eyJhdGgiOiJzVjhkZ1ZLcFExTHZpa1lrNmVvOEd2RGZhYkpyMWd0VlhrdkRnazdxLVpZIiwiYmFfaW52IjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIiwiYmFfb3AiOiJyZWFkIiwiYmFfcmVxIjoidXYyMFBpQzh0UlFvT3k5LWVSbEJGUFFuZ3RpRFhrd19TQ2JiZ3p4akMyZyIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUudGVzdC9pbnZva2UiLCJpYXQiOjExMDAsImp0aSI6InVybjpleGFtcGxlOnByb29mOjEiLCJ2IjoxfQ.BUONibEL8cesx2D905h2CwHhL8sdtZ33sABKd7jRl27UdBOo0jpQX9UGl8VLlpEVxSFiZlhBGwNg85VBakhwAw
  • Outcome: rejected — the single closed error value, no other observable <!-- examples:end -->

Appendix B. CDDL representation (informative) {#cddl}

An informative CDDL summary of the wire objects is published alongside this specification. It is NOT a machine-checked authority: the structural authority is the set of JSON Schemas and the conformance corpus (Appendix C). CDDL cannot express several closed-profile invariants (duplicate-name rejection at byte level, exact canonical encodings, raw lexeme bounds).

Appendix C. Reference mappings (informative)

The tagged algebra binds to the reference implementation's values as follows (the same tagged-value notation the typed projection in (#datamodel) uses):

JSONElixir value
null:null
boolean{:boolean, boolean}
integer{:integer, integer}
non-integer number{:float, finite_float}
string{:string, UTF-8_binary}
array{:array, [value]}
object{:object, [{UTF-8_binary, value}]}

The frozen reference implementation of this profile is the bounded_authority_protocol package. Its public v1 façade is the following locked API surface (enforced by the package's architecture gate; listed here informatively):

untrusted_key_locator(binary(), Bounds.t() | map())
grant_signing_input(Grant.t(), Bounds.t() | map())
proof_signing_input(Proof.t(), Bounds.t() | map())
assemble_compact(SigningInput.t(), binary())
assemble_compact(SigningInput.t(), binary(), Bounds.t() | map())
decode_grant(binary(), Bounds.t() | map())
decode_proof(binary(), Bounds.t() | map())
verify_grant(binary(), TrustedIssuer.t(), ExpectedGrant.t())
check_envelope(Credentials.t(), ExpectedRequest.t())
request_digest(binary(), Json.value(), Bounds.t() | map())
encode_consumption_entry(ConsumptionEntry.t(), Bounds.t() | map())
check_chain(ChainInput.t(), ExpectedChain.t())
boundary_anchor_signing_input(BoundaryAnchor.t(), Bounds.t() | map())
key_transition_signing_input(KeyTransition.t(), Bounds.t() | map())
encode_anchored_export(AnchoredExportInput.t(), ExpectedExport.t())
verify_historical_anchor(binary(), HistoricalPublicKey.t(), ExpectedAnchor.t())
verify_key_transition(binary(), HistoricalPublicKey.t(), HistoricalPublicKey.t(),
  ExpectedKeyTransition.t())
verify_anchored_export(ArchivedObject.t(), HistoricalKeyChain.t(),
  ExpectedAnchoredExport.t())

The untrusted key locator returns exactly:

{:ok, %BoundedAuthorityProtocol.V1.KeyLocator{kid: kid, trust: :not_evaluated}}

The Elixir bindings map the tagged algebra as: :null, {:boolean, b}, {:integer, n}, {:float, f}, {:string, s}, {:array, [value]}, {:object, [{name, value}]}; the closed error value is {:error, :invalid}. Companion artifacts: the conformance corpus (283 cases over 28 surfaces, certified index digest and monotone revision integer in its revision.json sidecar), the structural JSON Schemas (Draft 2020-12), the requirement-to-conformance map (REQ1-* to corpus cells), the registries document, and the standards-track charter. The corpus is the machine-checked oracle; requirement identifiers and their evidence cells are enumerated in Appendix D.

Appendix D. Requirement inventory (informative)

Every REQ1-* identifier used in this document is defined exactly once in the requirement-to-conformance map, together with its conformance evidence cells; the inventory is published there and drift-gated against this document by the spec-facts machinery. This appendix intentionally carries no second copy: a duplicated inventory is a drift surface, not documentation.


Generated from spec/bap-v1.md rev 1 (the single normative authority).