Chio/Docs

ReferenceSDKsnew

.NET SDK

Backbay.Chio.Middleware is fail-closed ASP.NET Core middleware that evaluates every request against the chio sidecar and verifies its signed receipt before responding.

Package name vs. namespace

The NuGet package id is Backbay.Chio.Middleware. Types are imported from the Backbay.Chio namespace. The middleware references Microsoft.AspNetCore.App and needs no other runtime dependency.

Installation

bash
$ dotnet add package Backbay.Chio.Middleware

Requires a running chio sidecar, which defaults to http://127.0.0.1:9090 or the CHIO_SIDECAR_URL environment variable.

Quickstart

Register the services with AddChioProtection and insert the middleware with UseChioProtection. Both extension methods hang off the Backbay.Chio namespace.

Program.cs
using Backbay.Chio;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddChioProtection();

var app = builder.Build();
app.UseChioProtection();

app.MapGet("/pets", () => new { pets = Array.Empty<object>() });

app.Run();

The middleware is fail-closed. If the sidecar is unreachable the request is denied with a 502 and a structured JSON body. Denied evaluations return the verdict's HTTP status, defaulting to 403. Allowed requests flow to the next component only after the embedded receipt is authorization-checked and its signature verified, and carry an X-Chio-Receipt-Id response header pointing at the signed receipt.

Method allow-list

The middleware evaluates GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. Any other method short-circuits with a 405 and error code chio_evaluation_failed before the sidecar is contacted.

Configuration

AddChioProtection accepts an Action<ChioMiddlewareOptions> configure callback.

OptionDefaultPurpose
SidecarUrlCHIO_SIDECAR_URL env, else http://127.0.0.1:9090Base URL of the sidecar kernel.
TimeoutSeconds5Sidecar HTTP timeout.
OnSidecarErrordenyReserved no-op. Sidecar errors always fail closed.
IdentityExtractorheader-basedCustom caller extraction (IdentityExtractorDelegate).
RouteResolverraw pathMap (method, path) to a route pattern.
csharp
builder.Services.AddChioProtection(opts =>
{
    opts.SidecarUrl = "http://127.0.0.1:9090";
    opts.TimeoutSeconds = 5;
    opts.RouteResolver = (method, path) =>
        path.StartsWith("/pets/") ? "/pets/{petId}" : path;
});

A capability token is read from the X-Chio-Capability header or the chio_capability query parameter and its embedded id forwarded to the sidecar. A complete example with controllers and a custom identity extractor lives at examples/hello-dotnet in the chio repository.

Identity Extraction

ChioIdentityExtractor.DefaultExtract reads, in order, an Authorization: Bearer token, an X-API-Key header, the first cookie, then falls back to an anonymous identity. Each branch hashes the credential with SHA-256 and records the method on AuthMethod; the raw secret never leaves the process. Override it with your own IdentityExtractorDelegate.

csharp
builder.Services.AddChioProtection(opts =>
{
    opts.IdentityExtractor = request =>
    {
        var tenant = request.Headers["X-Tenant"].FirstOrDefault();
        return new CallerIdentity
        {
            Subject = request.Headers["X-User"].FirstOrDefault() ?? "anonymous",
            AuthMethod = AuthMethod.Bearer("..."),
            Tenant = tenant,
        };
    };
});

ChioSidecarClient

The middleware wraps ChioSidecarClient, which you can also use standalone. It serializes with snake_case naming and drops null fields to match the sidecar wire contract.

MethodEndpointReturns
EvaluateAsyncPOST /chio/evaluateEvaluateResponse
VerifyReceiptAsyncPOST /chio/verifyVerifyReceiptResponse
HealthCheckAsyncGET /chio/healthbool

EvaluateAsync does not trust an allow-shaped response on its face. Whenever the verdict or the embedded receipt looks like an allow, it re-verifies through /chio/verify and requires VerifyReceiptResponse.Authorizes to hold before returning; otherwise it throws ChioSidecarException with code chio_invalid_receipt.

csharp
using Backbay.Chio;

using var client = new ChioSidecarClient("http://127.0.0.1:9090");

var request = new ChioHttpRequest
{
    RequestId = Guid.NewGuid().ToString(),
    Method = "GET",
    RoutePattern = "/pets",
    Path = "/pets",
    Caller = CallerIdentity.CreateAnonymous(),
    Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
};

var result = await client.EvaluateAsync(request);
if (result.Verdict.IsAllowed() && result.Receipt.IsAuthorized())
{
    Console.WriteLine(result.Receipt.Id);
}

Types

The type graph in Backbay.Chio mirrors the Rust chio-http-core crate and the JVM SDK. Each carries JsonPropertyName bindings to the snake_case wire names.

TypeRole
ChioHttpRequestRequest posted to /chio/evaluate.
CallerIdentity / AuthMethodExtracted caller and how it authenticated.
VerdictKernel verdict; VerdictType serializes as verdict.
HttpReceiptSigned receipt; IsAuthorized() encodes the mediated-authorization predicate.
EvaluateResponseVerdict + Receipt + Evidence.
VerifyReceiptResponseAuthority result from /chio/verify; Authorizes() is the strict gate.
GuardEvidencePer-guard evaluation evidence.

HttpReceipt.IsAuthorized() requires ReceiptKind == "mediated_decision", BoundaryClass == "prevent", TrustLevel == "mediated", a null ObservationOutcome, and an allow verdict. Authorizes() layers on top of that: the verify response must confirm the signature, signer trust, receipt-id and parameter-hash validity, a lower-hex 64-character id and content hash, and a non-empty signature. See the Receipt Format for the full field set.

Errors

ChioSidecarException carries a Code and an optional StatusCode. The middleware maps it to the response: an invalid receipt becomes a 502 with chio_invalid_receipt, any other sidecar failure a 502 with chio_sidecar_unreachable, and a denied verdict the verdict status with chio_access_denied.

csharp
try
{
    var result = await client.EvaluateAsync(request);
}
catch (ChioSidecarException ex)
{
    Console.WriteLine($"{ex.Code}: {ex.Message}");
}

The codes on ChioErrorCodes chio_access_denied, chio_sidecar_unreachable, chio_evaluation_failed, chio_invalid_receipt, chio_timeout — are the same strings the sidecar returns and match the Schemas & Errors taxonomy. The structured deny body carries error, message, receipt_id, and a suggestion.

The wire formats track the chio 0.1.x sidecar contract. For the cross-language invariants every SDK conforms against, see the Bindings API; for the shared HTTP evaluation contract, the HTTP Substrate.