Cirreum.SignedRequest
1.0.0
dotnet add package Cirreum.SignedRequest --version 1.0.0
NuGet\Install-Package Cirreum.SignedRequest -Version 1.0.0
<PackageReference Include="Cirreum.SignedRequest" Version="1.0.0" />
<PackageVersion Include="Cirreum.SignedRequest" Version="1.0.0" />
<PackageReference Include="Cirreum.SignedRequest" />
paket add Cirreum.SignedRequest --version 1.0.0
#r "nuget: Cirreum.SignedRequest, 1.0.0"
#:package Cirreum.SignedRequest@1.0.0
#addin nuget:?package=Cirreum.SignedRequest&version=1.0.0
#tool nuget:?package=Cirreum.SignedRequest&version=1.0.0
Cirreum.SignedRequest
HTTP Message Signatures and Content-Digest primitives for .NET, with a shared signature base that keeps Cirreum signers and verifiers aligned.
Overview
Cirreum.SignedRequest is the pure, dependency-free core of the SignedRequest scheme: the RFC 9421 / RFC 9530 building blocks that the server-side scheme (Cirreum.Authentication.SignedRequest) and the client SDK (Cirreum.Authentication.SignedRequest.Client) consume identically, so a signed request verifies byte-for-byte on both sides.
SignatureBaseBuilder— builds the RFC 9421 signature base (the ordered, labelled"component": valuelines terminated by"@signature-params") and serializes the signature-params value. The verifier replays the received params verbatim, so its reconstructed base is byte-identical to what was signed.SignatureBaseComponents.FromRequest(...)— the single value normalizer (method casing,@queryform, empty-path default, case-insensitive field keys). Per-side adapters project onto it, so canonicalization happens in exactly one place rather than drifting across signer and verifier.SignatureWireParser/ParsedSignature— defensive RFC 8941 parsing of theSignature/Signature-Inputheaders; every malformation returnsfalserather than throwing.ContentDigest— RFC 9530Content-Digestcompute and constant-time verify (SHA-256), binding the request body into the signature regardless of method.ISignedRequestAlgorithm/ISignedRequestAlgorithmResolver— the pluggable signing / verification seam, withHmacSha256SignedRequestAlgorithm(hmac-sha256) built in; new algorithms register additively.HttpRequestMessage.SignRequestAsync(...)/HttpClient.SendSignedAsync(...)— the ready-made outbound signer (withOutboundSigningOptionsandSigningCredentials, inSystem.Net.Http). This is the single signer the server scheme and the client SDK both surface, so a request signed on either side verifies byte-identically on the other.
It has no dependencies beyond the BCL — no Cirreum, ASP.NET, or third-party packages.
Installation
dotnet add package Cirreum.SignedRequest
Usage
Most applications don't use this package directly — they use the server scheme (Cirreum.Authentication.SignedRequest) or the client SDK (Cirreum.Authentication.SignedRequest.Client), both of which build on these primitives. Reach for it directly only to integrate RFC 9421 signing / verification into a custom surface.
The signer and verifier build the same base from the same components:
using Cirreum.SignedRequest;
// One place canonicalizes request primitives — both sides call it identically:
var components = SignatureBaseComponents.FromRequest(
method: "POST",
path: "/api/orders",
query: "?page=1",
fields: [new("content-digest", ContentDigest.Compute(body))]);
var parameters = new SignatureParameters {
CoveredComponents = ["@method", "@path", "@query", "content-digest"],
KeyId = "svc-a",
Algorithm = "hmac-sha256",
Created = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Nonce = nonce, // client-generated, >= 128-bit
};
// Signer — build the base, sign it, emit Signature / Signature-Input:
var signing = SignatureBaseBuilder.BuildForSigning(components, parameters);
var signature = new HmacSha256SignedRequestAlgorithm().Sign(signing.SignatureBase, keyBytes);
// Verifier — parse the headers, rebuild the byte-identical base, verify:
SignatureWireParser.TryParse(signatureInput, signatureHeader, out var entries);
var entry = entries[0];
var baseBytes = SignatureBaseBuilder.BuildBase(components, entry.CoveredComponents, entry.SignatureParamsValue);
var ok = new HmacSha256SignedRequestAlgorithm().Verify(baseBytes, entry.Signature, keyBytes)
&& ContentDigest.Verify(contentDigestHeader, body);
RFC conformance profile
Cirreum SignedRequest implements a constrained Cirreum profile of RFC 9421 and RFC 9530. The implementation intentionally supports the covered components, algorithms, digest forms, and validation behavior documented here; unsupported general RFC features are out of scope unless explicitly listed.
| Area | Supported | Not supported |
|---|---|---|
| Covered components | @method, @path, @query, HTTP fields (content-digest) |
@authority (intentionally dropped), @target-uri, @scheme, @status (response signing), @query-param, component parameters (sf / key / bs / req) |
| Algorithms | hmac-sha256 |
others are additive via ISignedRequestAlgorithm (e.g. Ed25519) |
| Digest (RFC 9530) | Content-Digest with sha-256 |
other digest algorithms (ignored), Repr-Digest / Want-*-Digest |
| Signatures per request | exactly one | multi-signature messages are rejected |
| Structured fields (RFC 8941) | the dictionary / inner-list / string / byte-sequence / integer subset these headers use | a general RFC 8941 parser |
SignatureBaseComponents.FromRequest normalizes @path / @query to the RFC 9421 §2.2.6/§2.2.7 + RFC 3986 §6.2.2 canonical form in this one shared place, so a signer and verifier on different hosts converge on the byte-identical base. Conformance is verified against RFC 4231 (HMAC-SHA-256) and RFC 9530 (Content-Digest) published test vectors, the signature base is locked by a known-answer vector, and the wire parser is fuzz-hardened against the RFC 9421 §7 never-throw contract.
Contribution Guidelines
Be conservative with new abstractions
The API surface must remain stable and meaningful.Limit dependency expansion
This package is intentionally BCL-only; keep it that way.Favor additive, non-breaking changes
Breaking changes ripple through the entire ecosystem.Include thorough unit tests
All primitives should be independently testable, with cross-surface conformance over awkward inputs.Document architectural decisions
Context and reasoning should be clear for future maintainers.Follow .NET conventions
Use established patterns from the BCL and Microsoft.Extensions.* libraries.
Versioning
Cirreum.SignedRequest follows Semantic Versioning:
- Major - Breaking API changes
- Minor - New features, backward compatible
- Patch - Bug fixes, backward compatible
License
This project is licensed under the MIT License - see the LICENSE file for details.
Cirreum Foundation Framework
Layered simplicity for modern .NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Cirreum.SignedRequest:
| Package | Downloads |
|---|---|
|
Cirreum.Authentication.SignedRequest
SignedRequest authentication scheme for the Cirreum framework. Verifies RFC 9421 HTTP Message Signatures (HMAC-SHA256, with a pluggable algorithm resolver) and RFC 9530 Content-Digest for partner / M2M integrations, and signs outbound requests. Ships the authentication handler, ISchemeSelector, the dynamic credential resolver, and the strict-nonce replay posture. |
|
|
Cirreum.Authentication.SignedRequest.Client
Client SDK for RFC 9421 HTTP Message Signatures. Sign outgoing HTTP requests and validate incoming webhooks (HMAC-SHA256, with RFC 9530 Content-Digest) — the full-duplex client counterpart to the server-side Cirreum.Authentication.SignedRequest scheme, built on the shared Cirreum.SignedRequest primitives. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 189 | 7/3/2026 |