| Internet-Draft | CAT-4-MOQT | June 2026 |
| Law, et al. | Expires 20 December 2026 | [Page] |
A token-based authorization scheme for use with Media Over QUIC Transport.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://moq-wg.github.io/CAT-4-MOQT/. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-ietf-moq-c4m/.¶
Discussion of this document takes place on the Media Over QUIC mailing list (mailto:moq@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/moq/. Subscribe at https://www.ietf.org/mailman/listinfo/moq/.¶
Source for this draft and an issue tracker can be found at https://github.com/moq-wg/CAT-4-MOQT.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 20 December 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
This draft introduces a token-based authorization scheme for use with MOQT [MoQTransport]. The scheme protects access to the relay during session establishment and also contrains the actions which the client may take once connected.¶
This draft defines version 1 of this specification.¶
This draft uses a single token format, namely the Common Access Token (CAT) [CAT]. The token is supplied as a byte array. When it must be cast to a string for inclusion in a URL, it is Base64 encoded [BASE64].¶
To provide control over the MOQT actions, this draft defines a new CBOR Web Token (CWT) Claim called "moqt". Use of the moqt claim is optional for clients. Support for processing the moqt claim is mandatory for relays.¶
The default for all actions is "Blocked" and this does not need to be communicated in the token. As soon as a token is provided, all actions are explicitly blocked unless explicitly enabled.¶
The "moqt" claim is defined by the following CDDL:¶
$$Claims-Set-Claims //= (moqt-label => moqt-value) moqt-label = TBD_MOQT moqt-value = [ + moqt-scope ] moqt-scope = [ moqt-actions, ? [ + moqt-ns-match ], ? moqt-track-match ] moqt-actions = [ + moqt-action ] moqt-action = int moqt-ns-match = bin-match / nil moqt-track-match = bin-match bin-match = bstr / [ match-type, match-value ] match-type = prefix-match / suffix-match match-value = bstr prefix-match = 1 suffix-match = 2¶
The "moqt" claim bounds the scope of MOQT actions for which the token can provide access. It is an array of action scopes. Each scope is an array with three elements: an array of integers that identifies the actions, an array of match objects for the namespace, and a match object for the track name.¶
The actions are integers defined as follows:¶
| Action | Key | Reference |
|---|---|---|
| CLIENT_SETUP | 0 | [MoQTransport] Section 9.3 |
| SERVER_SETUP | 1 | [MoQTransport] Section 9.3 |
| PUBLISH_NAMESPACE | 2 | [MoQTransport] Section 9.20 |
| SUBSCRIBE_NAMESPACE | 3 | [MoQTransport] Section 9.25 |
| SUBSCRIBE | 4 | [MoQTransport] Section 9.9 |
| REQUEST_UPDATE | 5 | [MoQTransport] Section 9.11 |
| PUBLISH | 6 | [MoQTransport] Section 9.13 |
| FETCH | 7 | [MoQTransport] Section 9.16 |
| TRACK_STATUS | 8 | [MoQTransport] Section 9.19 |
The scope of the moqt claim is limited to the actions provided in the array. Any action not present in the array is not authorized by moqt claim.¶
When a match object is a byte string, it is an exact match. When a match object is an array, the first element is the match type and the second is the match value.¶
Matches are performed bytewise against the corresponding field of the Full Track Name (as defined in Section 2.4.1 of [MoQTransport]). The first namespace match object is applied to the first field in the Track Namespace, and so on. The match for the track name is matched against the Track Name.¶
Exact matches must match exactly, prefix matches must match the beginning of the byte string, and suffix matches must match the end of the byte string.¶
The track namespace match and track name match are optional. If the length of the scope array is two, then no track name match is performed at all and the scope of the token includes all track names. If the length is one, the scope includes all namespaces as well as no matching is performed. The list of actions is mandatory.¶
A nil match object is special: it only matches the end of the list of namespaces. This allows the scope to be limited to a precise namespace length. If the list of namespace match objects does not end with a nil match object, then the scope includes all longer namespaces that start with fields that match. Note that nil MUST only appear as the last element in the namespace match array; placing nil elsewhere is invalid.¶
No normalization is applied to the values against which to match; it is performed bytewise.¶
Full Track Names in this draft are represented using Extended Diagnostic Notation (EDN) as defined in [EDN] as an array with two elements: an array of namespace fields and a track name.¶
Example: Allow with an exact match [['example','com'],'/bob']¶
{
/moqt/ TBD_MOQT: [[
[ /ANNOUNCE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7 ],
['example','com',nil],
'/bob'
]]
}
¶
Permits * [['example','com'], '/bob'] Prohibits * [['example','com'], ''] * [['example','com'], '/bob/123'] * [['example','com'], '/alice'] * [['example','com'], '/bob/logs'] * [['alternate','example','com'], '/bob'] * [['12345'], ''] * [['example'], 'com/bob'] * [['example','com','/bob'], ''] * [['example','com',''], '/bob']¶
Example: Allow with a prefix match [['example','com'],'/bob']¶
{
/moqt/ TBD_MOQT: [[
[ /ANNOUNCE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7 ],
['example','com',nil],
[ /prefix/ 1, '/bob']
]]
}
¶
Permits * [['example','com'], '/bob'] * [['example','com'], '/bob/123'] * [['example','com'], '/bob/logs'] Prohibits * [['example','com'], ''] * [['example','com'], '/alice'] * [['alternate','example','com'], '/bob'] * [['12345'], ''] * [['example'], 'com/bob']¶
Example: Allow namespaces starting with ['example','com'] (any length) with exact track name '/bob'¶
{
/moqt/ TBD_MOQT: [[
[ /PUBLISH_NAMESPACE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7 ],
{ /exact/ 0: 'example.com'},
{ /exact/ 0: '/bob'}
]]
}
¶
Permits * [['example','com'], '/bob'] * [['example','com',''], '/bob'] * [['example','com','bob'], '/bob'] Prohibits * [['example','com'], ''] * [['example','com'], '/bob/123'] * [['example','com'], '/alice'] * [['example','com'], '/bob/logs'] * [['alternate','example','com'], '/bob'] * [['12345'], ''] * [['example'], 'com/bob'] * [['example','com','/bob'], '']¶
Example: Allow namespaces starting with ['example','com'] with any track name¶
{
/moqt/ TBD_MOQT: [[
[ /PUBLISH_NAMESPACE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7 ],
['example','com']
]]
}
¶
Permits * [['example','com'], '/bob'] * [['example','com',''], '/bob'] * [['example','com','bob'], '/bob'] * [['example','com'], ''] * [['example','com'], '/bob/123'] * [['example','com'], '/alice'] * [['example','com'], '/bob/logs'] * [['example','com','/bob'], ''] Prohibits * [['alternate','example','com'], '/bob'] * [['12345'], ''] * [['example'], 'com/bob']¶
Example: Allow with a prefix match on an individual namespace element¶
This example shows how to use a prefix match within a specific namespace field. The second namespace element must start with 'user-'.¶
{
/moqt/ TBD_MOQT: [[
[ /ANNOUNCE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7 ],
['example', [ /prefix/ 1, 'user-'], nil],
'/data'
]]
}
¶
Permits * [['example','user-alice'], '/data'] * [['example','user-bob'], '/data'] * [['example','user-'], '/data'] Prohibits * [['example','alice'], '/data'] * [['example','user-alice','extra'], '/data'] * [['example','USER-alice'], '/data'] * [['example'], '/data']¶
Example: Allow with a suffix match on track name¶
This example demonstrates suffix matching, which matches the end of a byte string.¶
{
/moqt/ TBD_MOQT: [[
[ /PUBLISH/ 6 ],
['example','com',nil],
[ /suffix/ 2, '.json']
]]
}
¶
Permits * [['example','com'], 'data.json'] * [['example','com'], '/api/response.json'] * [['example','com'], '.json'] Prohibits * [['example','com'], 'data.xml'] * [['example','com'], 'json'] * [['example','com'], 'data.JSON'] * [['example','com'], 'data.json.bak']¶
Multiple actions may be communicated within the same token, with different permissions. This can be facilitated by the logical claims defined in [Composite] or simply by defining multiple limits, depending on the required restrictions. In both cases, the order in which limits are declared and evaluated is unimportant. The evaluation stops after the first acceptable result is discovered.¶
{
/moqt/ TBD_MOQT: [
[[/PUBLISH/ 6], ['example','com',nil], [ /prefix/ 1, '/bob']],
[[/PUBLISH/ 6], ['example','com',nil], '/logs/12345/bob']
],
/exp/ 4: 1750000000
}
¶
(1) PUBLISH (Allow with a prefix match on track name) [['example','com'], '/bob*']¶
(2) PUBLISH (Allow with an exact match) [['example','com'], '/logs/12345/bob']¶
Evaluating [['example','com'],'/bob/123'] would succeed on test 1 and test 2 would never be evaluated.
Evaluating [['example','com'],'/logs/12345/bob'] would fail on test 1 but then succeed on test 2.
Evaluating [['example','com'],''] would fail on test 1 and on test 2.¶
In addition, the entire token expires at 2025-05-02T21:57:24+00:00.¶
The "moqt-reval" claim is defined by the following CDDL:¶
$$Claims-Set-Claims //= (moqt-reval-label => moqt-reval-value) moqt-reval-label = TBD_MOQT_REVAL moqt-reval-value = number¶
The "moqt-reval" claim indicates that the token must be revalidated for ongoing streams. If the token is no longer acceptable, the actions authorized by it MUST NOT be permitted to continue.¶
The "moqt-reval-value" is a revalidation interval, expressed in seconds. It provides an upper bound on how long a token may be considered acceptable for an ongoing stream. A revalidator MAY revalidate sooner.¶
If the revalidation interval is smaller than the recipient is prepared or able to revalidate, the recipient MUST reject the token. If a recipient is unable to revalidate tokens, it MUST reject all tokens with a "moqt-reval" claim.¶
A token can be revalidated by simply validating it again, just as if it were new. However, since some claims, signatures, MACs, and other attributes that could contribute to unacceptability may be incapable of changing acceptability in the duration, a revalidator may optimize by skipping some of the checks as long as the outcome of the validation is the same. Revalidators SHOULD skip reverifying MACs and signatures when the list of acceptable issuer keys is unchanged.¶
When the value of this claim is zero, the token MUST NOT be revalidated. This is the default behaviour when the claim is not present.¶
This claim MUST NOT be used outside of a base claimset. If used within a composition claims, the token is not well-formed.¶
The claim key for this claim is TBD_MOQT_REVAL and the claim value is a number. Recipients MUST support this claim. This claim is OPTIONAL for issuers.¶
This section defines the use of CAT's Demonstrating Proof of Possession (DPoP) claims [DPoP] to enhance security in MOQT environments. This approach leverages the CAT token's "cnf" (confirmation) claim with JWK Thumbprint binding and the "catdpop" (CAT DPoP Settings) claim to provide proof-of-possession capabilities that prevent token theft and replay attacks in MOQT systems.¶
This proposal extends the CAT authorization model by binding tokens to client cryptographic key pairs. To enable sender-constrained token usage, the CAT tokens include DPoP-related claims as defined [CAT] Section 4.8, ensuring that only the legitimate token holder can use the token for MOQT operations.¶
DPoP binding is accomplished by providing the "cnf" claim with the "jkt" (JWK Thumbprint) confirmation method.¶
Below is an example showing jkt token binding.¶
{
/ cnf / 8: {
/ jkt / 3: h'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' / 32-byte SHA-256 JWK thumbprint (hex-encoded) /
},
/ moqt / TBD_MOQT: [
[
[/PUBLISH_NAMESPACE/ 2, /SUBSCRIBE_NAMESPACE/ 3, /PUBLISH/ 6, /FETCH/ 7],
['cdn','example','com',nil],
[ /prefix/ 1, '/sports/']
]
],
/ catdpop /
321: {
0: 300, / 5-minute window /
1: 1 / Honor jti for replay protection /
},
/ exp /
4: 1750000000
}
¶
Implementation Requirements:¶
Relay Validation: MOQT relays MUST verify that DPoP proofs are signed with the private key corresponding to the "jkt" value¶
Proof Binding: Relays MUST reject requests where DPoP proof validation or key binding fails¶
Processing Semantics: Relays MUST process DPoP proofs as Protected Resource Access requests per [DPoP] Section 7¶
This section defines the use of DPoP with an application-agnostic proof framework as specified in [DPOP-PROOF], which extends the traditional HTTP-centric DPoP model to support arbitrary protocols including MOQT. This approach replaces HTTP-specific claims with a flexible authorization context structure that can accommodate protocol-specific command representations.¶
The DPoP proof JWT follows the structure defined in Section 4 of [DPOP-PROOF] with the following required claims:¶
JWT Header:¶
"typ": "dpop-proof+jwt"¶
"alg": Asymmetric signature algorithm identifier¶
"jwk": Public key for verification¶
JWT Payload:¶
For MOQT operations, the Authorization Context ("actx") object contains:¶
"type": "moqt" (registered identifier for MOQT protocol)¶
"action": MOQT action identifier¶
"tns": Track namespace (required)¶
"tn": Track name (required)¶
"resource": MOQT resource identifier (optional)¶
When the optional "resource" parameter is included, it MUST be consistent with the
"tns" and "tn" parameters. The resource URI should follow the format
moqt://<relay-endpoint>?tns=<namespace>&tn=<track> where the tns and tn query
parameters match the respective "tns" and "tn" fields in the Authorization Context.¶
Example DPoP proof for MOQT PUBLISH_NAMESPACE operation:¶
{
"typ": "dpop-proof+jwt",
"alg": "ES256",
"jwk": { ... }
}
.
{
"jti": "unique-request-id",
"iat": 1705123456,
"actx": {
"type": "moqt",
"action": "PUB_NS",
"tns": "sports",
"tn": "live-feed"
}
}
¶
MOQT action mapping for Authorization Context:¶
| MOQT Action | actx.action |
|---|---|
| CLIENT_SETUP | SETUP |
| SERVER_SETUP | SETUP |
| PUBLISH_NAMESPACE | PUB_NS |
| SUBSCRIBE_NAMESPACE | SUB_NS |
| SUBSCRIBE | SUBSCRIBE |
| REQUEST_UPDATE | REQ_UPDATE |
| PUBLISH | PUBLISH |
| FETCH | FETCH |
| TRACK_STATUS | TRK_STATUS |
Relays supporting this application-agnostic DPoP framework MUST:¶
Validate DPoP proofs according to [DPOP-PROOF]¶
Verify that the "actx.type" is "moqt" for MOQT operations¶
Validate that the "actx.action" matches the requested MOQT action¶
Verify that the "actx.tns" corresponds to the target track namespace¶
Verify that the "actx.tn" corresponds to the target track name¶
If present, verify the "actx.resource" is consistent with "tns" and "tn"¶
Reject requests where Authorization Context validation fails¶
The Authorization Context "resource" field should specify track namespace (tns) and track name (tn) parameters for MOQT resources:¶
The following process illustrates how DPoP proof provision results in CAT token binding and subsequent MOQT relay validation:¶
┌──────────────┐ ┌─────────────────────┐ ┌──────┐
│MOQT Client │ │Authorization Server │ │MOQT │
│ │ │ │ │Relay │
└──────┬───────┘ └──────────┬──────────┘ └──────┘
│ │ │
│ (1) Generate Key Pair │ │
│ EC P-256/RSA │ │
│ private_key, public_key │ │
│ │ │
│ (2) Authentication Request │ │
│ + User Credentials │ │
│ + Public Key (JWK format) │ │
├──────────────────────────────────►│ │
│ │ │
│ │ (3) User Authentication │
│ │ & Authorization │
│ │ │
│ │ (4) Generate CAT Token: │
│ │ • "cnf" claim with │
│ │ "jkt": SHA256(public_key)│
│ │ • "catdpop" processing │
│ │ settings │
│ │ • "moqt" action scope │
│ │ • Sign with shared secret │
│ │ │
│ (5) CAT Token Response │ │
│ + Bound CAT Token │ │
│ + Relay Endpoint URL │ │
|◄──────────────────────────────────┤ │
│ │ │
¶
Steps 1-5 Detail:¶
Client Key Generation: The MOQT client generates an asymmetric key pair (typically EC P-256) for DPoP operations¶
Authentication with Public Key: Client authenticates with the authorization server, providing user credentials and the public key¶
User Authentication: Authorization server validates user identity and permissions¶
CAT Token Generation: Server creates a CAT token containing:¶
Token Delivery: Server provides the bound CAT token and relay endpoint information to the client¶
┌──────────────┐ ┌─────────────────────┐ ┌───────┐
│MOQT Client │ │Authorization Server │ │MOQT │
│ │ │ │ │Relay │
└──────┬───────┘ └──────────┬──────────┘ └──────┬┘
│ │ │
│ │ │
│ (6) For each MOQT action: │ │
│ Create fresh DPoP proof JWT │ │
│ • Header: typ="dpop-proof+jwt"│ │
│ • alg, jwk │ │
│ • Claims: jti, iat, actx │ │
│ • Sign with private_key │ │
│ │ │
│ (7) MOQT Request │ │
│ + CAT Token │ │
│ + Fresh DPoP Proof │ │
│ (CLIENT_SETUP, PUBLISH_NAMESPACE,│ │
│ SUBSCRIBE, PUBLISH, FETCH) │ │
├─────────────────────────────────────────────────────────────────────►│
│ │ │
│ │ (8)│
│ │ CAT Validation: │
│ │ • Verify token │
│ │ signature │
│ │ • Validate claims│
│ │ including exp, |
| | scope │
│ │ │
│ │ (9)│
│ │ DPoP Validation: │
│ │ • Extract "jkt" │
│ │ from token │
│ │ • Verify DPoP │
│ │ JWT signature │
│ │ • Validate key │
│ │ binding │
│ │ • Check │
│ │ freshness │
│ │ │
│ │ (10)│
│ │ Action Authorization│
│ │ • Match action │
│ │ to token scope│
│ │ • Check ns/track│
│ │ permissions │
│ │ │
│ (11) Response │ │
│ Success/Error │ │
◄─────────────────────────────────────────────────────────────────────┤
│ │ │
¶
Steps 6-11 Detail:¶
DPoP Proof Creation: For each MOQT action, the client creates a fresh DPoP proof JWT with:¶
MOQT Request: Client sends MOQT action with both CAT token and fresh DPoP proof¶
CAT Token Validation: Relay validates:¶
DPoP Proof Validation: Relay performs:¶
Extract "jkt" (JWK Thumbprint) from CAT token's "cnf" claim¶
Verify DPoP JWT signature using embedded public key¶
Confirm that SHA-256 hash of DPoP public key matches "jkt" value¶
Check proof freshness within "catdpop" window settings¶
Process replay protection based on "jti" settings¶
Validate Authorization Context ("actx") according to [DPOP-PROOF]¶
Verify "actx.type" is "moqt"¶
Validate "actx.action" matches the requested MOQT action¶
Verify "actx.tns" and "actx.tn" correspond to target resources¶
Action Authorization: Relay validates the specific MOQT action against token scope and namespace/track permissions¶
Response: Relay responds with success or appropriate error information¶
Any time an application wishes to add a CAT token to a URL or path element, the token SHOULD first be Base64 encoded [BASE64]. The syntax and method of modifying the URL is left to the application to define and is not constrained by this specification.¶
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.¶
IANA will register the following claims in the "CBOR Web Token (CWT) Claims" registry:¶
| moqt | moqt-reval | |
|---|---|---|
| Claim Name | moqt | moqt-reval |
| Claim Description | MOQT Action | MOQT revalidation |
| JWT Claim Name | N/A | N/A |
| Claim Key | TBD_MOQT (1+2) | TBD_MOQT (1+2) |
| Claim Value Type | array | number |
| Change Controller | IESG | IESG |
| Specification Document | RFCXXXX | RFCXXXX |
[RFC Editor: Please replace RFCXXXX with the published RFC number for this document.]¶
This document registers the following entry in the "MOQT Auth Token Type" registry established by [MoQTransport]:¶
| Token Type | Token Name | Specification |
|---|---|---|
| 0x01 | CAT | RFCXXXX |
When the Auth Token Type is set to 0x01, the Token Payload field contains a Common Access Token (CAT) [CAT] serialized as a CBOR-encoded CWT (CBOR Web Token).¶
The token MUST be processed according to the validation rules defined in this specification. Relays receiving a token with this type MUST:¶
Validate the token signature or MAC¶
Verify token expiration and other standard CWT claims¶
Process the "moqt" claim (if present) to authorize MOQT actions¶
Process the "moqt-reval" claim (if present) for revalidation requirements¶
Process DPoP claims (if present) according to Section 3 of this document¶
If the token fails validation, the relay MUST reject the connection or action with an appropriate error.¶
This appendix provides test vectors in JSON format for cross-implementation validation of CAT tokens for MOQT. Token strings use the base64url encoding defined in [BASE64] with the three-part structure: header.payload.signature.¶
The following keys are used throughout these test vectors:¶
{
"es256_private_key":
"c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721",
"es256_public_key_x":
"60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
"es256_public_key_y":
"7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
"hmac_sha256":
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
}
¶
These vectors validate correct CBOR encoding of individual claim types.¶
[
{
"id": "cbor_issuer_only",
"description": "Minimal token with only issuer claim",
"claims": {
"iss": "https://auth.example.com"
},
"payload_cbor_hex":
"a101781868747470733a2f2f617574682e6578616d706c652e636f6d"
},
{
"id": "cbor_core_claims",
"description": "All core CWT claims (iss, aud, exp, nbf, cti)",
"claims": {
"iss": "https://auth.example.com",
"aud": ["https://relay.example.com"],
"exp": 1700086400,
"nbf": 1700000000,
"cti": "test-token-001"
},
"payload_cbor_hex":
"a501781868747470733a2f2f617574682e6578616d706c652e636f6d03
81781968747470733a2f2f72656c61792e6578616d706c652e636f6d04
1a65554280051a6553f100074e746573742d746f6b656e2d303031"
},
{
"id": "cbor_cat_version_usage",
"description": "CAT version string and usage limit",
"claims": {
"catv": "CAT-v1",
"catu": 5
},
"payload_cbor_hex":
"a2190136664341542d763119013805"
},
{
"id": "cbor_network_identifiers",
"description": "Network identifiers: IP, CIDR, ASN, ASN range",
"claims": {
"catnip": [
{"type": "ip_address", "value": "192.168.1.100"},
{"type": "ip_range", "value": "10.0.0.0/8"},
{"type": "asn", "value": 64512},
{"type": "asn_range", "value": [64512, 64768]}
]
},
"payload_cbor_hex":
"a1190137846d3139322e3136382e312e313030a16869705f72616e6765
6a31302e302e302e302f38a16361736e19fc00a16961736e5f72616e67
658219fc0019fd00"
},
{
"id": "cbor_geographic_claims",
"description": "Geographic claims: coordinates, geohash, ISO 3166, altitude",
"claims": {
"geohash": "9q8yyk",
"catgeoiso3166": ["US", "CA"],
"catgeocoord": {"lat": 37.7749, "lon": -122.4194, "accuracy": 100.0},
"catgeoalt": 10
},
"payload_cbor_hex":
"a419011a6639713879796b19013c8262555362434119013da3636c6174
fb4042e32fec56d5d0636c6f6efbc05e9ad77318fc506861636375726
16379f956401901 3e0a"
},
{
"id": "cbor_uri_patterns",
"description": "URI patterns: exact, prefix, suffix",
"claims": {
"cath": [
{"type": "exact", "value": "https://example.com/live/stream1"},
{"type": "prefix", "value": "https://example.com/vod/"},
{"type": "suffix", "value": ".m3u8"}
]
},
"payload_cbor_hex":
"a119013b83782068747470733a2f2f6578616d706c652e636f6d2f6c6
976652f73747265616d31a166707265666978781868747470733a2f2f65
78616d706c652e636f6d2f766f642fa166737566666978652e6d337538"
},
{
"id": "cbor_alpn",
"description": "ALPN protocol identifiers",
"claims": {
"catalpn": ["moq-00", "h3"]
},
"payload_cbor_hex":
"a119013a82666d6f712d3030626833"
}
]
¶
These vectors validate the full token structure (header.payload.signature) with cryptographic verification.¶
[
{
"id": "token_hmac_minimal",
"description": "Minimal token signed with HMAC-SHA256",
"algorithm": "HMAC-SHA256",
"algorithm_id": -4,
"claims": {
"iss": "https://auth.example.com",
"aud": ["https://relay.example.com"],
"exp": 1700086400
},
"header_cbor_hex": "a201231063434154",
"header_b64": "ogEjEGNDQVQ",
"payload_cbor_hex":
"a301781868747470733a2f2f617574682e6578616d706c652e636f6d
0381781968747470733a2f2f72656c61792e6578616d706c652e636f
6d041a65554280",
"payload_b64":
"owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeBlodHRwczovL3
JlbGF5LmV4YW1wbGUuY29tBBplVUKA",
"signature_hex":
"5b5ec60fb1a3f81d18b5e8d7edf4702e55261248def8c13cd6809cf6
865a6986",
"signature_b64":
"W17GD7Gj-B0YtejX7fRwLlUmEkje-ME81oCc9oZaaYY",
"key_hex":
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b
1c1d1e1f",
"token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeB
lodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKA.W17GD7Gj-B0Y
tejX7fRwLlUmEkje-ME81oCc9oZaaYY",
"valid": true
},
{
"id": "token_hmac_full",
"description":
"Token with core + CAT + informational claims, HMAC-SHA256",
"algorithm": "HMAC-SHA256",
"algorithm_id": -4,
"claims": {
"iss": "https://issuer.moq.example",
"sub": "user:alice@example.com",
"aud": [
"https://relay1.example.com",
"https://relay2.example.com"
],
"exp": 1700086400,
"nbf": 1700000000,
"iat": 1700000000,
"cti": "vector-002",
"catv": "CAT-v1",
"catnip": [{"type": "ip_address", "value": "203.0.113.50"}],
"catu": 10
},
"header_cbor_hex": "a201231063434154",
"header_b64": "ogEjEGNDQVQ",
"payload_cbor_hex":
"aa01781a68747470733a2f2f6973737565722e6d6f712e6578616d70
6c650276757365723a616c696365406578616d706c652e636f6d0382
781a68747470733a2f2f72656c6179312e6578616d706c652e636f6d
781a68747470733a2f2f72656c6179322e6578616d706c652e636f6d
041a65554280051a6553f100061a6553f100074a766563746f722d30
3032190136664341542d7631190137816c3230332e302e3131332e35
301901380a",
"payload_b64":
"qgF4Gmh0dHBzOi8vaXNzdWVyLm1vcS5leGFtcGxlAnZ1c2VyOmFsa
WNlQGV4YW1wbGUuY29tA4J4Gmh0dHBzOi8vcmVsYXkxLmV4YW1wbG
UuY29teBpodHRwczovL3JlbGF5Mi5leGFtcGxlLmNvbQQaZVVCgAUa
ZVPxAAYaZVPxAAdKdmVjdG9yLTAwMhkBNmZDQVQtdjEZATeBbDIwMy
4wLjExMy41MBkBOAo",
"signature_hex":
"02aa58a31e34ab53fab3c755b47cf08f458a3603da4d933d7c0b1ce4
614f44da",
"signature_b64":
"AqpYox40q1P6s8dVtHzwj0WKNgPaTZM9fAsc5GFPRNo",
"key_hex":
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b
1c1d1e1f",
"token":
"ogEjEGNDQVQ.qgF4Gmh0dHBzOi8vaXNzdWVyLm1vcS5leGFtcGxlAn
Z1c2VyOmFsaWNlQGV4YW1wbGUuY29tA4J4Gmh0dHBzOi8vcmVsYXkx
LmV4YW1wbGUuY29teBpodHRwczovL3JlbGF5Mi5leGFtcGxlLmNvbQQ
aZVVCgAUaZVPxAAYaZVPxAAdKdmVjdG9yLTAwMhkBNmZDQVQtdjEZAT
eBbDIwMy4wLjExMy41MBkBOAo.AqpYox40q1P6s8dVtHzwj0WKNgPaTZ
M9fAsc5GFPRNo",
"valid": true
},
{
"id": "token_es256",
"description":
"Token signed with ES256 (P-256 ECDSA, deterministic RFC 6979)",
"algorithm": "ES256",
"algorithm_id": -7,
"claims": {
"iss": "https://auth.example.com",
"aud": ["https://moq-relay.example.com"],
"exp": 1700086400,
"nbf": 1700000000
},
"header_cbor_hex": "a201261063434154",
"header_b64": "ogEmEGNDQVQ",
"payload_cbor_hex":
"a401781868747470733a2f2f617574682e6578616d706c652e636f6d
0381781d68747470733a2f2f6d6f712d72656c61792e6578616d706c
652e636f6d041a65554280051a6553f100",
"payload_b64":
"pAF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeB1odHRwczovL2
1vcS1yZWxheS5leGFtcGxlLmNvbQQaZVVCgAUaZVPxAA",
"signature_hex":
"fa3315e9de061fd77d814394428ae61da3d7a21fdffb19802b0c575c
578098e7cd4b6b75a1690deed4c2baae994bfc462e0d8a2006f3e897
80f3435738294d7a",
"signature_b64":
"-jMV6d4GH9d9gUOUQormHaPXoh_f-xmAKwxXXFeAmOfNS2t1oWkN7t
TCuq6ZS_xGLg2KIAbz6JeA80NXOClNeg",
"private_key_hex":
"c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b
120f6721",
"public_key_x_hex":
"60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e
60f29fb6",
"public_key_y_hex":
"7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294
d4462299",
"token":
"ogEmEGNDQVQ.pAF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeB
1odHRwczovL21vcS1yZWxheS5leGFtcGxlLmNvbQQaZVVCgAUaZVPxA
A.-jMV6d4GH9d9gUOUQormHaPXoh_f-xmAKwxXXFeAmOfNS2t1oWkN7
tTCuq6ZS_xGLg2KIAbz6JeA80NXOClNeg",
"valid": true
}
]
¶
These vectors validate DPoP (Demonstrating Proof-of-Possession) key binding in CAT tokens.¶
[
{
"id": "dpop_jwk_binding",
"description":
"Token with DPoP key binding (JWK thumbprint in cnf claim)",
"dpop": {
"cnf_jkt_hex":
"a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1",
"window_seconds": 60,
"honor_jti": true
},
"payload_cbor_hex":
"a401781868747470733a2f2f617574682e6578616d706c652e636f6d
041a6555428008a1035820a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6
f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1190141a200183c0101",
"token":
"ogEjEGNDQVQ.pAF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaZV
VCgAihA1ggoLHC0-T1prfI2eDxorPE1eb3qLnA0eLzpLXG1-j5oLEZA
UGiABg8AQE.sN9kLIp64zIN9zDXoTLYC0xsJU_1FNF3kaO0CbdA_3M"
},
{
"id": "dpop_no_jti",
"description":
"DPoP binding with longer window, JTI processing disabled",
"dpop": {
"cnf_jkt_hex":
"3c82dfd6358ba804bd90879c34e743bbe13aeab7980664944f37a0ec0063fe95",
"cnf_jkt_source": "SHA-256 of 'test-public-key-material'",
"window_seconds": 300,
"honor_jti": false
},
"payload_cbor_hex":
"a401781868747470733a2f2f617574682e6578616d706c652e636f6d
041a6555428008a10358203c82dfd6358ba804bd90879c34e743bbe13a
eab7980664944f37a0ec0063fe95190141a20019012c0100",
"token":
"ogEjEGNDQVQ.pAF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaZV
VCgAihA1ggPILf1jWLqAS9kIecNOdDu-E66reYBmSUTzeg7ABj_pUZA
UGiABkBLAEA.M4lF5pQdxav6eIWqDjbchDkijVYOM7xa3oJR2IwWt9g"
},
{
"id": "dpop_es256_real_binding",
"description":
"ES256 token with real JWK thumbprint binding to the signing key",
"algorithm": "ES256",
"jwk_thumbprint_input":
"{\"crv\":\"P-256\",\"kty\":\"EC\",\"x\":\"YP7UuiVanTHJYet0xjVtaMBJuJI7Yfps5mliLmDyn7Y\",\"y\":\"eQP-EAi4vJmkGunpVii8ZPLxsgwtfp9Rd6PClNRGIpk\"}",
"dpop": {
"cnf_jkt_hex":
"0cebf1bc9880748a95588905b79843b42ba75cb174055e3e246bf87fe00b4a6d",
"window_seconds": 120,
"honor_jti": null
},
"public_key_x_hex":
"60fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6",
"public_key_y_hex":
"7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299",
"payload_cbor_hex":
"a501781868747470733a2f2f617574682e6578616d706c652e636f6d
0381781968747470733a2f2f72656c61792e6578616d706c652e636f6d
041a6555428008a10358200cebf1bc9880748a95588905b79843b42ba7
5cb174055e3e246bf87fe00b4a6d190141a1001878",
"token":
"ogEmEGNDQVQ.pQF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeB
lodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKACKEDWCAM6_G8m
IB0ipVYiQW3mEO0K6dcsXQFXj4ka_h_4AtKbRkBQaEAGHg.5andoxOh
WXQIKWR3EMHWT-WIMPBDMYQFc61nzlfZs8zmgzwcOARpmlaB3ZS5MbJ
9iCYWykYAcIzJ81nMyyZoQw"
}
]
¶
These vectors validate token processing: expected pass and fail scenarios. All tokens use HMAC-SHA256 with the key specified in the Keys section unless otherwise noted.¶
[
{
"id": "valid_basic",
"description":
"Valid token with correct issuer, audience, and time bounds",
"token":
"ogEjEGNDQVQ.pAF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeBlodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKABRplU_EA.9SztgnG4xgw8U9zDFnqPIuPn6hLwuilSigQcfPsArSg",
"validation": {
"reference_time": 1700003600,
"expected_issuers": ["https://auth.example.com"],
"expected_audiences": ["https://relay.example.com"],
"expected_result": "valid"
}
},
{
"id": "invalid_expired",
"description": "Token with expiration in the past",
"token":
"ogEjEGNDQVQ.ogF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaX14QAA.lq8nGBiZm80yUwl1kH_Tv2prKu_nV20JvxVJW8ZGkho",
"validation": {
"reference_time": 1700000000,
"expected_result": "error",
"expected_error": "TokenExpired"
}
},
{
"id": "invalid_not_yet_valid",
"description": "Token with not-before in the future",
"token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaZVaUAAUaZVVCgA.fPIUugY7_oSeHlheu83_8Yyljsk3iP2zGeWRUi7NtUs",
"validation": {
"reference_time": 1700000000,
"expected_result": "error",
"expected_error": "TokenNotYetValid"
}
},
{
"id": "invalid_wrong_issuer",
"description": "Token from untrusted issuer",
"token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vZXZpbC5leGFtcGxlLmNvbQOBeBlodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKA.Xo7FCr_MGSyVX0C9sueeapSfboIHkrkysurn2VjC9PU",
"validation": {
"reference_time": 1700003600,
"expected_issuers": ["https://auth.example.com"],
"expected_result": "error",
"expected_error": "InvalidIssuer"
}
},
{
"id": "invalid_wrong_audience",
"description": "Token not intended for this audience",
"token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeB9odHRwczovL290aGVyLXJlbGF5LmV4YW1wbGUuY29tBBplVUKA.b8KxAKxJglzhELMuc9bYmsikrx3F9Y3YdvpfHLbsyk0",
"validation": {
"reference_time": 1700003600,
"expected_issuers": ["https://auth.example.com"],
"expected_audiences": ["https://relay.example.com"],
"expected_result": "error",
"expected_error": "InvalidAudience"
}
},
{
"id": "invalid_tampered_signature",
"description":
"Token with corrupted signature (first byte flipped)",
"original_token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeBlodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKA.W17GD7Gj-B0YtejX7fRwLlUmEkje-ME81oCc9oZaaYY",
"token":
"ogEjEGNDQVQ.owF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQOBeBlodHRwczovL3JlbGF5LmV4YW1wbGUuY29tBBplVUKA.pF7GD7Gj-B0YtejX7fRwLlUmEkje-ME81oCc9oZaaYY",
"validation": {
"expected_result": "error",
"expected_error": "SignatureVerificationFailed",
"key_hex":
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
}
},
{
"id": "invalid_wrong_key",
"description": "Token verified with incorrect key",
"token":
"ogEjEGNDQVQ.ogF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaZVVCgA.zmbxdkvbWtGtX0DExLC2nIxPDDmgAVImqk4rRSCCkCY",
"validation": {
"correct_key_hex":
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"wrong_key_hex":
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"expected_result": "error",
"expected_error": "SignatureVerificationFailed"
}
},
{
"id": "invalid_algorithm_mismatch",
"description":
"Token header says HMAC-SHA256 but verifier expects ES256",
"token":
"ogEjEGNDQVQ.ogF4GGh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbQQaZVVCgA.zmbxdkvbWtGtX0DExLC2nIxPDDmgAVImqk4rRSCCkCY",
"validation": {
"token_algorithm_id": -4,
"verifier_algorithm_id": -7,
"expected_result": "error",
"expected_error": "AlgorithmMismatch"
}
}
]
¶
The IETF moq workgroup¶