| Internet-Draft | HashBack | October 2026 |
| Godfrey | Expires 26 April 2027 | [Page] |
HashBack is a two-step authentication exchange carried over HTTPS/TLS
that allows one HTTP server to authenticate another, without either
party holding a long-term shared secret, bearer token, or private
key. A prover demonstrates its identity by publishing a short cryptographic
hash on a website it controls; the verifier of a request fetches
that hash over a second, independent HTTPS connection and compares
it against a value it calculates itself. If the two values match,
the verifier is reassured that the prover is who it claims to be.
This document describes the HashBack exchange, the format of the
Authorization header it defines, and the security
considerations that apply to implementations.¶
This note is to be removed before publishing as an RFC.¶
This document uses "NNNN" as a placeholder for its own RFC number
in the Version string "RFC_NNNN" (see the Version member in
Section 5.1, and the example
WWW-Authenticate header that follows the discovery
description). Please replace every occurrence of NNNN with the
number assigned to this document, then remove this note.¶
The example Authorization header field in
Section 5.1 and the expected verification hash in
Section 6 are both computed from the example JSON
object, which currently carries the Version value
"BILLPG_DRAFT_4.2". If that example is changed to show "RFC_NNNN"
instead, those two values must be regenerated rather than
text-substituted - replacing NNNN alone would leave them wrong,
since they are derived from the exact bytes of the JSON. The
authors will supply the regenerated values. (The Fixed Salt does
not depend on the Version value and is unaffected.)¶
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 26 April 2027.¶
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.¶
A server that calls out to another server over the Internet typically needs some way to prove its identity: an API key, a bearer token, a shared secret, or a private key backing a client TLS certificate. Whichever form it takes, that credential has to be generated, distributed to the calling service, stored securely at both ends, and eventually rotated - all before the two services can exchange a single authenticated request.¶
HashBack removes the need for that long-term credential entirely. Instead, it relies on a property both parties already have if they are communicating over HTTPS at all: each side runs a TLS-secured web server that the other side can reach. HashBack uses this in a manner similar to a phone call placed to a trusted number and then immediately hung up so the other side can call back: the prover tells the verifier "I am the operator of this URL - call me back there to check", and publishes a value at that URL for the verifier to retrieve.¶
This is deliberately similar in spirit to the challenge exchange used by the Automatic Certificate Management Environment (ACME) [RFC8555], which validates control of a domain name by asking the requester to publish a token there ahead of a certificate being issued. HashBack applies the same "prove control of a URL" idea to general-purpose API authentication, and reduces the exchange to two HTTP transactions instead of three.¶
This document is an early, individual Internet-Draft. It has not been adopted by any IETF working group. It is published to invite review and comment ahead of a future submission for standardization.¶
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.¶
This document additionally uses the following terms:¶
In outline, the Prover builds a JSON object describing the request
it is about to make, including the URL where it will publish that
object's hash. It sends this object, Base64-encoded, in the HTTP
Authorization header of its request. Before or immediately
after sending that request, it publishes the object's verification
hash at the declared URL.¶
On receiving the request, the Verifier parses the
Authorization header, applies its own policy checks (see
Section 7), and then makes a separate HTTPS GET
request to the Verify URL to retrieve the published hash. The
Verifier computes the same hash itself from the bytes it received
and compares the two values. If they match, the Verifier has
confirmed that whoever controls the Verify URL endorses this
specific request, and processes it accordingly.¶
Two independent HTTPS connections are used: the original request, and the Verifier's GET request to the Verify URL. Because TLS secures both connections, and because the published value is a hash of the specific request rather than a fixed shared secret, this exchange requires no pre-agreed credential beyond the Verifier knowing which range of Verify URLs belong to which Prover (see Section 4).¶
Before this exchange can take place, the Verifier MUST have a way to map an incoming Verify URL to a specific, known Prover identity. Exactly how this mapping is established and stored is outside the scope of this document (it might be an entry in a configuration file, a row in a database populated through a self-service web portal, or a value baked into deployment configuration), but the range of URLs accepted for any one Prover MUST be narrow enough that no other party could plausibly publish content there.¶
A single fixed URL, or a URL varying only in a query string parameter or a restricted path segment, is appropriate. A URL prefix that could allow the Prover's other users to publish arbitrary content (for example, a path serving user comments or a public wiki) is not, because it would let an unrelated party impersonate the Prover by publishing a hash of their own choosing under that same prefix.¶
Examples of acceptable and unacceptable declarations:¶
| Pattern | Acceptable? | Reason |
|---|---|---|
| https://example.com/hashback?id=* | Yes | Single fixed path, varying only in a query parameter |
| https://example.com/hashback/*.txt | Yes | Single restricted folder, no further subfolders |
| http://example.com/hashback/* | No | Not protected by TLS |
| https://example.com/* | No | Too broad; covers content the Prover does not control |
| https://example.com/blog/* | No | May allow third-party comments |
The Prover authenticates its request using the HTTP
Authorization request header field, using the auth-scheme
token HashBack:¶
Authorization = "HashBack" 1*SP token68¶
where token68 is as defined by
Section 11.3 of [RFC9110]. The token68 value
MUST be the standard Base64 encoding
(Section 4 of [RFC4648], including
padding, and without line breaks) of a JSON object, encoded as
UTF-8, described below. (Line breaks shown in examples in this
document are for presentation only and are not part of the header
value.)¶
The JSON object MUST be a JSON object, as defined by [RFC8259], containing exactly the following members. All values are strings unless stated otherwise. All members are REQUIRED.¶
BILLPG_DRAFT_4.2", the label it already carries in
the reference implementation and in the informal, pre-IETF
drafts that preceded this document. A future revision of this
document, once
adopted as an IETF work item, is expected to define a new
version string of the form "RFC_NNNN", where NNNN is
the number ultimately assigned to that RFC.¶
Host header, this property carries an authoritative
copy included in the hashed material, so there is no ambiguity
about which name the Prover intended. The Verifier
MUST reject any request whose Host
property does not match one of its own recognized names,
including generic names such as "localhost" that
belong to no specific service. See
Section 10.2.¶
=" padding. Every other
property of this JSON object is potentially predictable to an
attacker; the security of this exchange depends on this value,
and only this value, being unpredictable (see
Section 10.3). A Prover
MUST NOT reuse a Unus value across
requests. A Verifier SHOULD reject any request
reusing a Unus value it has already seen within its
configured Now tolerance window.¶
https:// URL, belonging to the Prover, from which
the Verifier can retrieve the verification hash with an HTTP
GET request. This URL MUST fall within a range
the Verifier has already associated with a specific Prover
identity, per Section 4.¶
If either the Host or Verify property would
otherwise contain a non-ASCII internationalized domain name, that
name MUST be normalized and represented either as
literal UTF-8 or using JSON's \u escape notation, and
MUST NOT use the ToASCII ("xn--") form.¶
For example, the following JSON object:¶
{
"Version": "BILLPG_DRAFT_4.2",
"Host": "server.example",
"Now": 529297200,
"Unus": "Rpgt4Fc5nMDq14LOps/hYQ==",
"Verify": "https://client.example/api/hashback?id=502542886"
}
¶
is Base64-encoded and sent as the following
Authorization header field:¶
Both the Prover and the Verifier compute the verification hash the
same way, from the same bytes: the exact UTF-8 byte sequence that
was (or will be) Base64-decoded from the Authorization
header. The hash MUST be computed as follows:¶
=" padding.¶
The Fixed Salt is the following 32 bytes:¶
48,106,239,61,141,188,122,117, 71,242,89,164,154,89,44,47, 20,42,34,245,250,230,139,30, 56,240,40,168,35,184,92,252¶
equivalently, in Base64:
MGrvPY28enVH8lmkmlksLxQqIvX65oseOPAoqCO4XPw=, or in
hexadecimal:
306AEF3D8DBC7A7547F259A49A592C2F142A22F5FAE68B1E38F028A823B85CFC.¶
The Fixed Salt is NOT a secret. Its only purpose is to ensure a HashBack verification hash cannot be confused with, or produced by, an unrelated general-purpose hashing service, since that service would not have prepended this same value. It was generated using PBKDF2 with the following parameters, provided here for transparency and reproducibility rather than as part of the algorithm implementers need to run:¶
The expected verification hash for the example request in
Section 5.1 is
/+Zc/xVCVgnnfC69tEybe2TAluOk21ScdystX0/1Ayk=.¶
Once computed, the Prover MUST publish the verification hash at the Verify URL before, or without excessive delay after, sending the authenticated request, so that it is available by the time the Verifier fetches it. The response to a GET request for the Verify URL MUST:¶
200 OK status code;¶
The Verifier compares the hash it downloads against the hash it
computes itself from the bytes it decoded from the
Authorization header. If the Verifier cannot retrieve a
matching hash - because of a network failure, an unexpected status
code, a certificate problem, or a mismatched value - it
MUST treat the request as unauthenticated and
respond with a suitable HTTP error, with enough detail in the
response to help a reasonably experienced developer correct the
problem.¶
On receiving a request bearing a HashBack
Authorization header, the Verifier
MUST perform the following checks, in any order,
before treating the request as authenticated:¶
Authorization header
uses the HashBack auth-scheme, and its token68 value
Base64-decodes to a well-formed JSON object with all the members
listed in Section 5.1.¶
Version property is one this Verifier implements.¶
Host property is a name this Verifier recognizes as
itself (see Section 10.2).¶
Now property is within the Verifier's configured
tolerance of its own clock.¶
Unus property is well-formed and, if replay
protection is configured, has not already been seen.¶
Verify property is an HTTPS URL the Verifier can
map to a specific, known Prover identity, per
Section 4.¶
Verify URL
matches the hash the Verifier computes itself, per
Section 6.¶
If every check passes, the Verifier treats the request as
authenticated as the Prover identity associated with the
Verify URL, and proceeds to process the request that
carried the header. If any check fails, the Verifier
MUST NOT process the request and
SHOULD respond with an HTTP 4xx status
code.¶
A Verifier rejecting an unauthenticated request with a
401 response MAY advertise support for this
exchange using a WWW-Authenticate response header field
Section 11.6.1 of [RFC9110] whose auth-scheme is
HashBack. An optional realm auth-param
MAY be present. An optional version
auth-param, if present, MUST be a comma-separated
list of Version values this Verifier accepts, most
preferred first; a Prover SHOULD select a value from
this list when building its next request. Absence of the
version parameter does not imply that HashBack is
unsupported.¶
A Prover that already knows a Verifier supports HashBack
MAY send the Authorization header on its
first request, skipping this discovery step.¶
Every HashBack exchange requires a fresh JSON object, a freshly published verification hash, and therefore a second HTTPS round trip on the Verifier's side. This is inherently more expensive than reusing a bearer token, and this document intentionally does not define a token format or refresh mechanism to sit on top of it.¶
Implementations that need to authenticate many requests in
succession are RECOMMENDED to run one HashBack
exchange and then have the Verifier issue its own short-lived
credential - for example, a bearer token or a Set-Cookie
response header - that the Prover then presents for subsequent
requests until it expires, at which point the HashBack exchange is
repeated. The format, lifetime, and transport of that credential is
outside the scope of this document.¶
This exchange depends entirely on the security properties of TLS for both HTTP transactions. It provides no security of its own against an attacker capable of defeating TLS - such as one holding a certificate improperly issued by a trusted certificate authority - beyond whatever precautions an implementation separately takes, such as maintaining its own restricted set of trusted certificate authorities or pinning certificates for known Provers.¶
Without the Host property, a Verifier that is itself
malicious, or that has been compromised, could take a valid
request received from a genuine Prover and forward it unmodified
to a third Verifier, which would retrieve the same verification
hash and be fooled into believing it was talking directly to the
original Prover. Because Host is included in the hashed
material, a forwarded request would carry the wrong
Host value for the third Verifier, and
Section 7 requires that value be rejected. For this
reason, a Verifier MUST reject any request whose
Host property is not a name it recognizes as its own,
including generic names such as "localhost" that could
belong to any server.¶
With the exception of Unus, every property of the JSON
object described in Section 5.1 may be entirely
predictable to an attacker without weakening this exchange. An
attacker who can predict or observe a Verify URL and its
published hash still cannot construct a valid request for a
different Verifier, because doing so requires finding a JSON
object - including a Unus value - that hashes to that
same value, which is computationally infeasible against SHA-256.
Implementations therefore MUST generate
Unus using a cryptographically secure random number
generator, and MUST NOT reuse a value.¶
Fetching a URL supplied in an incoming request carries the usual SSRF risks associated with any user-supplied URL fetch. Implementations SHOULD apply the same precautions they would to any other outbound fetch of prover-supplied data: resolving and validating the destination address before connecting, rejecting internal or loopback address ranges unless explicitly intended (for example, during local development), declining to follow redirects (see Section 6), and applying a request timeout.¶
Because every incoming request with a HashBack header causes the
Verifier to make a further outbound HTTPS request, a flood of
fabricated Authorization headers could be used to
exhaust a Verifier's outbound connection capacity, even though
every one of those requests will ultimately fail verification.
Implementations SHOULD apply a short connection
and response timeout to the Verify URL fetch, and
MAY track and rate-limit sources of requests that
repeatedly fail verification.¶
A related concern is a malicious Verify URL that accepts the connection but never completes the response, tying up a connection on the Verifier for as long as it is willing to wait. A short, strictly enforced timeout on the Verify URL fetch mitigates this; the timeout only needs to be long enough for the expected response to arrive under normal network conditions.¶
This document requests registration of "HashBack" in the "Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry" defined by Section 16.4 of [RFC9110]:¶
| Field | Value |
|---|---|
| Authentication Scheme Name | HashBack |
| Pointer to specification text | This document |
| Notes | (none) |
This document defines no new media types, URI schemes, or other IANA registries at this time.¶
The author thanks Danny Wilson for feedback and for developing an independent implementation of this exchange; multiple independent implementations are valuable when establishing a new standard. The author also thanks "buzer" of Hacker News for raising the slow-verification-URL denial-of-service concern discussed in Section 10.5.¶
A reference implementation in C# ("HashBackCore"), along with a publicly reachable demo service exercising both the Prover and Verifier roles, is maintained alongside the source of this document at https://github.com/billpg/HashBack. Interested implementers are encouraged to test their own implementations against it and to report interoperability issues there.¶