# HMAC Validation (ASP.NET Core)

Adding HMAC (Hash-based Message Authentication Code) authentication to an ASP.NET Core application can help ensure that requests are authenticated and have not been tampered with. You can implement this as a custom middleware.

### The Middleware Class

The middleware will extract the necessary information from the request headers (e.g., Authorization header), calculate the HMAC signature, and compare it to the one provided by the client.

{% code lineNumbers="true" %}

```csharp
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Primitives;

public class HmacAuthenticationMiddleware(RequestDelegate next, string secretKey)
{
    private readonly RequestDelegate next = next;
    private readonly string secretKey = secretKey;

    public async Task Invoke(HttpContext context)
    {
        // Extract the HMAC signature from the Authorization header
        if (!context.Request.Headers.TryGetValue("Authorization", out StringValues authHeader))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Missing Authorization Header");
            return;
        }

        // The Authorization header should be in the format: HMAC <signature>
        string[] authParts = authHeader.ToString().Split(' ');
        if (authParts.Length != 2 || authParts[0] != "HMAC")
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid Authorization Header Format");
            return;
        }

        string providedSignature = authParts[1];

        // Calculate the HMAC of the request
        string calculatedSignature = await ComputeHmacSignature(context, secretKey);

        // Compare the provided signature with the calculated one
        if (!providedSignature.Equals(calculatedSignature, StringComparison.OrdinalIgnoreCase))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid Signature");
            return;
        }

        // Call the next middleware in the pipeline
        await next(context);
    }

    private static async Task<string> ComputeHmacSignature(HttpContext context, string secretKey)
    {
        // Read the request content
        context.Request.EnableBuffering();
        var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
        context.Request.Body.Position = 0;

        // Compute the HMAC SHA256 hash
        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
        byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(requestBody));
        return Convert.ToBase64String(hash);
    }
}
```

{% endcode %}

### Extension Method for Middleware

n .NET, extension methods for middleware registration encapsulate setup details, simplifying Startup.cs and promoting clean, reusable code. This convention hides complexity, providing a fluent and consistent way to add middleware to the request pipeline.

{% code lineNumbers="true" %}

```csharp
public static class HmacAuthenticationMiddlewareExtensions
{
    public static IApplicationBuilder UseHmacAuthentication(this IApplicationBuilder app, string secretKey)
    {
        ArgumentNullException.ThrowIfNull(app);

        return app.UseMiddleware<HmacAuthenticationMiddleware>(secretKey);
    }
}
```

{% endcode %}

### Register the Middleware

Register the middleware in your `Program.cs` or `Startup.cs` file. Use the HMAC secret key generated by Cubu.

{% code lineNumbers="true" %}

```csharp
app.UseHmacAuthentication("<HMAC secret key>");
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cubu.com/guides/technical-guide/webhooks/developing-webhooks/hmac-validation-asp.net-core.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
