Schemes
A scheme names headers whose values become part of the signature. On the client it is a name and a flat list of header names:
type HmacScheme = {
name: string;
headers: string[];
};There is no claimType here. When this package verifies, it hands the covered
values back on the result and stops there — see
below. Mapping them onto a principal is the .NET
handler’s job, and it needs a name to map onto.
const factory = new HmacManagerFactory([{
name: "MyPolicy",
publicKey: "00000000-0000-0000-0000-000000000001",
privateKey: "zvg29s2cQ4idOqbUJWETOw==",
contentHashAlgorithm: HashAlgorithm.SHA256,
signatureHashAlgorithm: HashAlgorithm.SHA256,
schemes: [{
name: "UserScheme",
headers: ["X-UserId", "X-Email"]
}]
}]);Select the scheme when creating the manager:
const manager = factory.create("MyPolicy", "UserScheme");The headers must already be on the request
The values are read off the request at signing time, so they have to be set first:
const request = new Request("https://api.example.com/orders", {
headers: {
"X-UserId": "42",
"X-Email": "someone@example.com"
}
});
const result = await manager.sign(request);If any header the scheme names is missing, signing fails — and it fails
quietly: sign returns isSuccess: false rather than throwing, with the
reason on result.error. Adding a header after signing is just as wrong, since
it is then not covered by the signature and the verifier rejects the request.
Always check isSuccess.
Order matters
The values are appended to the signing content in the order the scheme
declares its headers, not the order they appear on the request. Both sides must
declare them in the same order — ["X-UserId", "X-Email"] and
["X-Email", "X-UserId"] are different schemes as far as the signature is
concerned, even though they name the same headers.
Verifying with a scheme
Nothing extra to configure — the scheme is on the policy, and the request names which one it used. On success the covered values come back by header name:
const result = await verifier.verify(request);
if (result.isSuccess) {
const userId = result.headerValues!["X-UserId"];
}These are the only header values worth trusting on the request. They are inside the signature, so altering one in transit invalidates it; every other header travelled unprotected.
A request missing a header its scheme names fails with headers-missing — the
signature covers a value that is not there, so there is nothing to compare. See
verifying requests.
Server side
The matching .NET policy:
policy.AddScheme("UserScheme", scheme =>
{
scheme.AddHeader("X-UserId", ClaimTypes.NameIdentifier);
scheme.AddHeader("X-Email", ClaimTypes.Email);
});Or as an HmacPolicy resource:
schemes:
- name: UserScheme
headers:
- name: X-UserId
claimType: userId
- name: X-Email
claimType: email