An example HashBack session
Let's follow one request from the client's first thought to the server's final nod. Hashbert the Hedgehog will annotate the important bits, because authentication is easier to understand when someone points at the spiky details.

The client knows where it is calling
The client-side builder starts with the server host and a narrow HTTPS URL where the server can retrieve the verification hash.
var hashbackBuilder = new billpg.HashBackCore.AuthHeaderBuilder();
var auth = hashbackBuilder
.WithHost("server.example")
.WithVerify("https://client.example/api/hashback?id=502542886")
.Build();Hashbert says: "The Host tells me who you intend to visit. The Verify URL tells me where I may call you back. Keep that URL narrow and HTTPS-secure, please. I have standards, and also spines."
The client prepares two useful results
When Build() runs, it creates the authorization value and calculates the matching verification hash. The client sends the header to the server and publishes the hash at its verification URL.
Console.WriteLine("Auth Header: " + auth.AuthHeader);
Console.WriteLine("Verification Hash: " + auth.VerificationHash);
// Send auth.AuthHeader in the HTTP Authorization header.
// Return auth.VerificationHash from the Verify URL.Hashbert says: "One result travels to the server. One result waits on the client's website. They are a matched pair, like me and a carefully labelled laboratory notebook."
The request carries a claim, not a password
The authorization value contains a Base64-encoded JSON claim. In the README's example, the claim identifies the protocol version, destination host, current time, one-use random value, and callback URL.
Authorization: HashBack
eyJWZXJzaW9uIjoiQklMTFBHX0RSQUZUXzQuMiIsIkhvc3QiOiJzZXJ2ZXIuZXhhbXBsZSIsIk5v
dyI6NTI5Mjk3MjAwLCJVbnVzIjoiUnBndDRGYzVuTURxMTRMT3BzL2hZUT09IiwiVmVyaWZ5Ijoi
aHR0cHM6Ly9jbGllbnQuZXhhbXBsZS9hcGkvaGFzaGJhY2s/aWQ9NTAyNTQyODg2In0=Hashbert says: "This is not a secret being shared forever. It is a fresh, time-aware claim with a one-use value. The random Unus helps stop anyone from trying the same claim twice. Very sensible. Very prickly."
The server checks the callback
The receiving service configures a parser with the host it expects and a small clock tolerance, then parses the incoming header.
var hashbackParser = new billpg.HashBackCore.AuthHeaderParser()
.WithRequiredHost("server.example")
.WithTimeTolerance(10);
var parseResult = hashbackParser.Parse("eyHeaderTokenGoesHere==");
Console.WriteLine("Verify URL: " + parseResult.VerifyUrl);
Console.WriteLine("Expected Hash: " + parseResult.ExpectedHash);Hashbert says: "The server checks that the request is meant for it, that the timestamp is fresh, and that the verification URL belongs to a known client. If any of those wobble, the request stays outside the gate."
The server compares the two hashes
The server fetches the verification URL over HTTPS and compares the returned text with the expected hash calculated from the claim. A match reassures the server that the caller controls the registered verification URL.
Hashbert says: "That is the callback. The server has not received a long-lived password; it has received proof that the client can publish the right answer from the right HTTPS location. I approve this exchange with a thoughtful nod."