Codebelt

Codebelt.Extensions.AwsSignature4

Build and parse AWS Signature Version 4 authorization headers for ASP.NET Core requests.

.NET 10.0 / .NET 9.0 MIT v10.0.8 3,999 downloads

Overview

Codebelt.Extensions.AwsSignature4 builds and parses AWS4-HMAC-SHA256 authorization headers for ASP.NET Core HTTP requests. It extends the HMAC authentication abstractions in Cuemon.AspNetCore.Authentication with AWS-specific credential scope fields, canonical request generation, and signature calculation.

The package is centered on Aws4HmacAuthorizationHeaderBuilder. It reads request method, path, query string, headers, and payload hash from HttpRequest, combines them with AWS date, region, and service data, and emits an Aws4HmacAuthorizationHeader that can also be parsed back from a raw header string.

Key APIs

Aws4HmacAuthorizationHeaderBuilder is the main entry point for collecting request metadata and signing inputs before producing the final header. Because it inherits from the Cuemon HMAC builder, it works with inherited calls such as AddClientId and AddClientSecret while adding AWS Signature Version 4 behavior on top.

Aws4HmacAuthorizationHeaderBuilder.AddCredentialScope populates the AWS timestamp, date stamp, region, service, and composed credential scope in one call. Its defaults target S3 in eu-west-1, but region, service, and termination can be overridden when the request targets another AWS service or signing scope.

Aws4HmacAuthorizationHeaderBuilder.AddFromRequest extracts the HTTP method, canonical URI, sorted query string, canonicalized headers, and SHA-256 payload hash from an HttpRequest. This is the package method that turns an ASP.NET Core request into the canonical inputs AWS expects during signing.

Aws4HmacAuthorizationHeaderBuilder.Build validates that the required request and AWS scope fields are present, computes the signature, and returns the final HmacAuthorizationHeader. When no explicit signed-header list exists, it adds the default AWS set of host;x-amz-content-sha256;x-amz-date before building the header.

Aws4HmacAuthorizationHeaderBuilder.ComputeCanonicalRequest assembles the canonical request text from the collected request data and returns its SHA-256 digest. It is the API to inspect when you need to verify how the builder normalized headers, query parameters, and payload before the signature is calculated.

Aws4HmacAuthorizationHeaderBuilder.ComputeSignature derives the AWS4 signing key from the client secret, date, region, and service, stores the string-to-sign in the builder state, and returns the final signature as a hexadecimal string. This is the AWS-specific step that distinguishes the package from a generic HMAC header builder.

Aws4HmacAuthorizationHeader.Create parses a raw authorization header string back into a HmacAuthorizationHeader. Use it when you need to compare a generated header with a serialized value or rehydrate a header that already exists on an incoming request.

DateTimeExtensions.ToAwsDateTimeString and DateTimeExtensions.ToAwsDateString format DateTime values using the AWS basic timestamp and date formats used by the builder. They keep the date inputs aligned with the values that become part of the credential scope and string-to-sign.

Basic usage

using System;
using System.IO;
using Codebelt.Extensions.AwsSignature4;
using Codebelt.Extensions.Xunit;
using Cuemon.Security.Cryptography;
using Microsoft.AspNetCore.Http;
using Xunit;

namespace MyProject.Tests;

public class AwsSignature4HeaderBuilderTests : Test
{
    public AwsSignature4HeaderBuilderTests(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void Build_CreatesSignature_ForAnS3ListRequest()
    {
        var timestamp = new DateTime(2022, 7, 10, 12, 50, 42, DateTimeKind.Utc);
        var context = new DefaultHttpContext();
        context.Request.Method = HttpMethods.Get;
        context.Request.Path = "/";
        context.Request.QueryString = QueryString.Create("list-type", "2");
        context.Request.Body = new MemoryStream();
        context.Request.Headers["host"] = "cuemon.s3.amazonaws.com";
        context.Request.Headers["x-amz-date"] = timestamp.ToAwsDateTimeString();
        context.Request.Headers["x-amz-content-sha256"] = UnkeyedHashFactory.CreateCryptoSha256().ComputeHash("").ToHexadecimalString();

        var signedHeader = $"{new Aws4HmacAuthorizationHeaderBuilder()
            .AddFromRequest(context.Request)
            .AddClientId("AKIAIOSFODNN7EXAMPLE")
            .AddClientSecret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY")
            .AddCredentialScope(timestamp)
            .Build()}";

        TestOutput.WriteLine(signedHeader);

        Assert.Equal("AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220710/eu-west-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=3d2c4a14b38d0283bb697176ade57b2118110de0f00c387d7f0ef58c55a5b91d", signedHeader);
        Assert.Equal(signedHeader, $"{Aws4HmacAuthorizationHeader.Create(signedHeader)}");
    }
}

Use this pattern when you already have an HttpRequest and need to sign it for an AWS service such as S3 before the request is sent onward. It keeps the AWS-specific canonicalization, credential scope, and final header construction in one builder so the generated header can be inspected or parsed back deterministically.

Installation

dotnet add package Codebelt.Extensions.AwsSignature4

Usage guidance

Choose this package when your code is responsible for shaping or proxying HTTP requests and you need explicit control over the AWS Signature Version 4 authorization header, canonical request, and credential scope. If you only need generic HMAC authorization handling instead of AWS-specific date, region, service, and signing rules, the lower-level Cuemon.AspNetCore.Authentication package is the better fit.