From 0b98d55f0e20bdae3693a2df533311a31f01546e Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Wed, 1 Jul 2026 14:15:28 -0700 Subject: [PATCH 1/5] rephrase intro --- draft-richer-oauth-httpsig.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/draft-richer-oauth-httpsig.md b/draft-richer-oauth-httpsig.md index ea9c9e1..0d9eb59 100644 --- a/draft-richer-oauth-httpsig.md +++ b/draft-richer-oauth-httpsig.md @@ -17,6 +17,10 @@ author: organization: MongoDB email: ietf@justin.richer.org role: editor + - ins: A. Parecki + name: Aaron Parecki + organization: Okta + email: aaron@parecki.com normative: BCP195: @@ -49,18 +53,17 @@ HTTP Message Signatures to bind access tokens to keys held by OAuth 2.0 clients. # Introduction The OAuth 2.0 framework provides methods for clients to get delegated access tokens from an -authorization server for accessing protected resources. The access tokens at the center -of OAuth 2.0 can be bound to a variety of different mechanisms, including bearer tokens, -mutual TLS, or other presentation mechanisms. +authorization server for accessing protected resources. +Defined in RFC6750, OAuth access tokens are bearer tokens. Bearer tokens are simple to implement but also have the significant security downside of -allowing anyone who sees the access token to use that token. {{HTTPSIG}} defines a generic -mechanism that is used to sign HTTP requests and responses. +allowing anyone who sees the access token to use that token. + +{{HTTPSIG}} defines a generic mechanism that is used to sign HTTP requests and responses. This specification defines means to bind access tokens to a key held by the client, a token type -value and token response for indicating that a token is meant to be used with {{HTTPSIG}} -presentation, and a method for presenting bound access tokens in HTTP requests using -{{HTTPSIG}}. +value, a token response for indicating that a token is meant to be used with {{HTTPSIG}} +presentation, and a method for presenting bound access tokens in HTTP requests using {{HTTPSIG}}. This work complements and builds on experience with {{DPOP}} and {{MTLS}}, as well as implementations of {{I-D.ietf-oauth-signed-http-request}}, a spiritual predecessor to this @@ -76,7 +79,7 @@ This document contains non-normative examples of partial and complete HTTP messa # Requesting an HTTP Message Signature Bound Access Token {#binding} -To bind an access token to a key, the AS needs to know which key to bind to which token. This specification defines two common methods depending on the needs of the client: +To bind an access token to a key, the authorization server (AS) needs to know which key to bind to which token. This specification defines two common methods depending on the needs of the client: - A static method that depends on key material available as part of the client registration - A runtime method that allows a client to introduce key material during the token request phase of {{OAUTH}} From d615a19f2bd707760356c2aac3d3898648ab9ec4 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Wed, 1 Jul 2026 14:31:08 -0700 Subject: [PATCH 2/5] add client metadata for key binding method --- draft-richer-oauth-httpsig.md | 62 ++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/draft-richer-oauth-httpsig.md b/draft-richer-oauth-httpsig.md index 0d9eb59..eac1be6 100644 --- a/draft-richer-oauth-httpsig.md +++ b/draft-richer-oauth-httpsig.md @@ -41,6 +41,7 @@ normative: informative: I-D.ietf-oauth-signed-http-request: + I-D.ietf-oauth-client-id-metadata-document: SIGNED-INTROSPECTION: RFC9701 --- abstract @@ -84,15 +85,15 @@ To bind an access token to a key, the authorization server (AS) needs to know wh - A static method that depends on key material available as part of the client registration - A runtime method that allows a client to introduce key material during the token request phase of {{OAUTH}} -As part of its registration, a client MUST indicate which method it will use. +As part of its registration, a client MUST indicate which method it will use, using either the `httpsig_key_binding_method` client registration metadata parameter defined in {{iana-dynreg}} when using Dynamic Client Registration ({{DYNREG}}) or Client ID Metadata Document ({{I-D.ietf-oauth-client-id-metadata-document}}), or via an out of band method. -\[\[ Editor's note: do we want to add a client metadata parameter to signal this, as well as an AS/RS metadata parmaeter to signal support for each type? \]\] +\[\[ Editor's note: do we want to add an AS/RS metadata parameter to signal support for each type? \]\] \[\[ Editor's note: Are there any other patterns of key introduction we should cover? I put PAR in the appendix as a note. \]\] ## Pre-Registration of Keys {#preregister} -A client pre-registering its keys for {{HTTPSIG}} binding MUST include the key in its registered `jwks` value or make it available from its `jwks_uri` endpoint. The JWK MUST have a `kid` field and MUST indicate a signing algorithm in its `alg` field. The key ID for the public used for HTTP Message Signature bound access tokens MUST be identified using the `httpsig_bound_access_token_kid` field in the client's metadata. +A client pre-registering its keys for {{HTTPSIG}} binding MUST include the key in its registered `jwks` value or make it available from its `jwks_uri` endpoint. The JWK MUST have a `kid` field and MUST indicate a signing algorithm in its `alg` field. The key ID for the public key used for HTTP Message Signature bound access tokens MUST be identified using the `httpsig_bound_access_token_kid` field in the client's metadata. \[\[ Editor's note: do we want to have a client field for the signing alg or just leave that to the key all the time? I prefer to keep it in the key. \]\] @@ -104,7 +105,7 @@ Note that pre-registration can occur statically or dynamically (such as by using Instead of pre-registering a key, a client can introduce its key during the token request in the same fashion as {{DPOP}}. -The client MUST present its public key in the Signature-Key header field. The field is an HTTP Structured Field consisting of a Binary value containing the bytes of the {{JSON}} serialized {{JWK}} form of the key material. +The client MUST present its public key in the `Signature-Key` header field. The field is an HTTP Structured Field consisting of a Binary value containing the bytes of the {{JSON}} serialized {{JWK}} form of the key material. The JWK MUST have a `kid` field. The key MUST be a public key (and neither a private key nor a shared secret key). The JWK MUST have an `alg` value that indicates a signature algorithm. @@ -121,7 +122,7 @@ For example, the following JWK public key: } ~~~ -Can be encoded to the following Signature-Key field value (this example uses a compact JSON serialization that removes whitespace): +Can be encoded to the following `Signature-Key` field value (this example uses a compact JSON serialization that removes whitespace): ~~~ NOTE: '\' line wrapping per RFC 8792 @@ -136,9 +137,9 @@ Signature-Key: :eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5I\ ## Token Request {#request} -The presence of an HTTP Message Signature with the tag "httpsig-oauth-token-request" indicates that the client is requesting a bound token. The client MUST include a message signature of the indicated key. +The presence of an HTTP Message Signature with the tag `httpsig-oauth-token-request` indicates that the client is requesting a bound token. The client MUST include a message signature of the indicated key. -Additionally, the client MUST calculate and include the digest of the request body and include it as the Content-Digest header defined in {{DIGEST}}. +Additionally, the client MUST calculate and include the digest of the request body and include it as the `Content-Digest` header defined in {{DIGEST}}. For example, a form-encoded request body consisting of: @@ -149,7 +150,7 @@ grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA\ &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb ~~~ -Would create the following Content-Digest header: +Would create the following `Content-Digest` header: ~~~ Content-Digest: sha-256=:4fEzRVTGqfZg7lqf/d3oxXu837pvb3L0GN24+F1VkZk=: @@ -247,7 +248,7 @@ Authorization: HTTPSig 2340897.34j123-134uh2345n Authorization: httpsig 2340897.34j123-134uh2345n Authorization: HTTPSIG 2340897.34j123-134uh2345n Authorization: Httpsig 2340897.34j123-134uh2345n -Authorization: hTpTsIg 2340897.34j123-134uh2345n +Authorization: hTtPsIg 2340897.34j123-134uh2345n ~~~ When presenting an HTTP Message Signature bound access token to an RS, the client MUST include a signature compliant with {{HTTPSIG}}. The covered components MUST include: @@ -358,6 +359,49 @@ An RS receiving such a signed message and a bound access token MUST verify the H \[\[ TBD: register the token type and new parameters into their appropriate registries, as well as the JWT and introspection parameters needed for confirmation methods. \]\] +## OAuth Dynamic Client Registration Metadata {#iana-dynreg} + +This specification requests registration of the following client metadata name in the "OAuth Dynamic Client Registration Metadata" registry established by {{DYNREG}}. + +### httpsig_key_binding_method + +Client Metadata Name: +: `httpsig_key_binding_method` + +Client Metadata Description: +: Indicates which method the client uses to bind a key for HTTP Message Signature bound access tokens. The value MUST be one of `preregistered`, indicating that the client uses a key registered ahead of time as described in {{preregister}}, or `runtime`, indicating that the client introduces its key at the time of the token request as described in {{runtime}}. + +Change Controller: +: IETF + +Reference: +: This document + +#### Example + +A client can publish this parameter as part of a {{I-D.ietf-oauth-client-id-metadata-document}}, alongside its `jwks` and `httpsig_bound_access_token_kid` values. For example, a client with the `client_id` value `https://client.example.com/client-metadata.json` would publish the following document at that URL, indicating that it uses a pre-registered key: + +~~~ json +{ + "client_id": "https://client.example.com/client-metadata.json", + "client_name": "Example Client", + "jwks": { + "keys": [ + { + "kty": "OKP", + "use": "sig", + "crv": "Ed25519", + "kid": "j-0Ny45NWmqGq6GQ", + "x": "iuemcj_GhRHmY_yCsMlDNp3BQgPZDdG00VRsg_BgU3s", + "alg": "EdDSA" + } + ] + }, + "httpsig_bound_access_token_kid": "j-0Ny45NWmqGq6GQ", + "httpsig_key_binding_method": "preregistered" +} +~~~ + # Security Considerations {#Security} \[\[ TBD. \]\] From cec310a688e8ecc99511bffc0a4642bc512a0826 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Wed, 1 Jul 2026 14:52:01 -0700 Subject: [PATCH 3/5] header formatting Co-authored-by: Aaron Parecki --- draft-richer-oauth-httpsig.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/draft-richer-oauth-httpsig.md b/draft-richer-oauth-httpsig.md index eac1be6..73758db 100644 --- a/draft-richer-oauth-httpsig.md +++ b/draft-richer-oauth-httpsig.md @@ -105,7 +105,7 @@ Note that pre-registration can occur statically or dynamically (such as by using Instead of pre-registering a key, a client can introduce its key during the token request in the same fashion as {{DPOP}}. -The client MUST present its public key in the `Signature-Key` header field. The field is an HTTP Structured Field consisting of a Binary value containing the bytes of the {{JSON}} serialized {{JWK}} form of the key material. +The client MUST present its public key in the Signature-Key header field. The field is an HTTP Structured Field consisting of a Binary value containing the bytes of the {{JSON}} serialized {{JWK}} form of the key material. The JWK MUST have a `kid` field. The key MUST be a public key (and neither a private key nor a shared secret key). The JWK MUST have an `alg` value that indicates a signature algorithm. @@ -122,7 +122,7 @@ For example, the following JWK public key: } ~~~ -Can be encoded to the following `Signature-Key` field value (this example uses a compact JSON serialization that removes whitespace): +Can be encoded to the following Signature-Key field value (this example uses a compact JSON serialization that removes whitespace): ~~~ NOTE: '\' line wrapping per RFC 8792 @@ -139,7 +139,7 @@ Signature-Key: :eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5I\ The presence of an HTTP Message Signature with the tag `httpsig-oauth-token-request` indicates that the client is requesting a bound token. The client MUST include a message signature of the indicated key. -Additionally, the client MUST calculate and include the digest of the request body and include it as the `Content-Digest` header defined in {{DIGEST}}. +Additionally, the client MUST calculate and include the digest of the request body and include it as the Content-Digest header defined in {{DIGEST}}. For example, a form-encoded request body consisting of: @@ -150,7 +150,7 @@ grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA\ &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb ~~~ -Would create the following `Content-Digest` header: +Would create the following Content-Digest header: ~~~ Content-Digest: sha-256=:4fEzRVTGqfZg7lqf/d3oxXu837pvb3L0GN24+F1VkZk=: From a73049f04212fd9559875661efb484f9f16d899c Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Wed, 1 Jul 2026 15:01:09 -0700 Subject: [PATCH 4/5] remove IANA for now, add example instead --- draft-richer-oauth-httpsig.md | 70 +++++++++++++---------------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/draft-richer-oauth-httpsig.md b/draft-richer-oauth-httpsig.md index 73758db..0ebf40f 100644 --- a/draft-richer-oauth-httpsig.md +++ b/draft-richer-oauth-httpsig.md @@ -85,7 +85,7 @@ To bind an access token to a key, the authorization server (AS) needs to know wh - A static method that depends on key material available as part of the client registration - A runtime method that allows a client to introduce key material during the token request phase of {{OAUTH}} -As part of its registration, a client MUST indicate which method it will use, using either the `httpsig_key_binding_method` client registration metadata parameter defined in {{iana-dynreg}} when using Dynamic Client Registration ({{DYNREG}}) or Client ID Metadata Document ({{I-D.ietf-oauth-client-id-metadata-document}}), or via an out of band method. +As part of its registration, a client MUST indicate which method it will use, using either the `httpsig_key_binding_method` client registration metadata parameter defined (TBD) in {{IANA}} when using Dynamic Client Registration ({{DYNREG}}) or Client ID Metadata Document ({{I-D.ietf-oauth-client-id-metadata-document}}), or via an out of band method. \[\[ Editor's note: do we want to add an AS/RS metadata parameter to signal support for each type? \]\] @@ -101,6 +101,31 @@ A pre-registered key MAY be a shared secret (such as for use in an HMAC signatur Note that pre-registration can occur statically or dynamically (such as by using {{DYNREG}}), as long as the key is associated with the client's `client_id` before the token request is made. +### Example Client Registration + +A client can publish the key binding parameters as part of a {{I-D.ietf-oauth-client-id-metadata-document}} alongside its `jwks` or `jwks_uri` values. For example, a client with the `client_id` value `https://client.example.com/client-metadata.json` would publish the following document at that URL, indicating that it uses a pre-registered key: + +~~~ json +{ + "client_id": "https://client.example.com/client-metadata.json", + "client_name": "Example Client", + "jwks": { + "keys": [ + { + "kty": "OKP", + "use": "sig", + "crv": "Ed25519", + "kid": "j-0Ny45NWmqGq6GQ", + "x": "iuemcj_GhRHmY_yCsMlDNp3BQgPZDdG00VRsg_BgU3s", + "alg": "EdDSA" + } + ] + }, + "httpsig_bound_access_token_kid": "j-0Ny45NWmqGq6GQ", + "httpsig_key_binding_method": "preregistered" +} +~~~ + ## Token Request Key Introduction {#runtime} Instead of pre-registering a key, a client can introduce its key during the token request in the same fashion as {{DPOP}}. @@ -359,49 +384,6 @@ An RS receiving such a signed message and a bound access token MUST verify the H \[\[ TBD: register the token type and new parameters into their appropriate registries, as well as the JWT and introspection parameters needed for confirmation methods. \]\] -## OAuth Dynamic Client Registration Metadata {#iana-dynreg} - -This specification requests registration of the following client metadata name in the "OAuth Dynamic Client Registration Metadata" registry established by {{DYNREG}}. - -### httpsig_key_binding_method - -Client Metadata Name: -: `httpsig_key_binding_method` - -Client Metadata Description: -: Indicates which method the client uses to bind a key for HTTP Message Signature bound access tokens. The value MUST be one of `preregistered`, indicating that the client uses a key registered ahead of time as described in {{preregister}}, or `runtime`, indicating that the client introduces its key at the time of the token request as described in {{runtime}}. - -Change Controller: -: IETF - -Reference: -: This document - -#### Example - -A client can publish this parameter as part of a {{I-D.ietf-oauth-client-id-metadata-document}}, alongside its `jwks` and `httpsig_bound_access_token_kid` values. For example, a client with the `client_id` value `https://client.example.com/client-metadata.json` would publish the following document at that URL, indicating that it uses a pre-registered key: - -~~~ json -{ - "client_id": "https://client.example.com/client-metadata.json", - "client_name": "Example Client", - "jwks": { - "keys": [ - { - "kty": "OKP", - "use": "sig", - "crv": "Ed25519", - "kid": "j-0Ny45NWmqGq6GQ", - "x": "iuemcj_GhRHmY_yCsMlDNp3BQgPZDdG00VRsg_BgU3s", - "alg": "EdDSA" - } - ] - }, - "httpsig_bound_access_token_kid": "j-0Ny45NWmqGq6GQ", - "httpsig_key_binding_method": "preregistered" -} -~~~ - # Security Considerations {#Security} \[\[ TBD. \]\] From b76045de2751b321b5412ae8937f218c5955e8ae Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Wed, 1 Jul 2026 15:05:02 -0700 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Aaron Parecki --- draft-richer-oauth-httpsig.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-richer-oauth-httpsig.md b/draft-richer-oauth-httpsig.md index 0ebf40f..792950c 100644 --- a/draft-richer-oauth-httpsig.md +++ b/draft-richer-oauth-httpsig.md @@ -56,7 +56,7 @@ HTTP Message Signatures to bind access tokens to keys held by OAuth 2.0 clients. The OAuth 2.0 framework provides methods for clients to get delegated access tokens from an authorization server for accessing protected resources. -Defined in RFC6750, OAuth access tokens are bearer tokens. +OAuth access tokens can be bearer tokens, or bound to a variety of mechanisms including mutual TLS, DPoP, or other presentation mechanisms. Bearer tokens are simple to implement but also have the significant security downside of allowing anyone who sees the access token to use that token. @@ -80,7 +80,7 @@ This document contains non-normative examples of partial and complete HTTP messa # Requesting an HTTP Message Signature Bound Access Token {#binding} -To bind an access token to a key, the authorization server (AS) needs to know which key to bind to which token. This specification defines two common methods depending on the needs of the client: +To bind an access token to a key, the AS needs to know which key to bind to which token. This specification defines two common methods depending on the needs of the client: - A static method that depends on key material available as part of the client registration - A runtime method that allows a client to introduce key material during the token request phase of {{OAUTH}}