When a .NET application communicates with an AWS service, authentication is an important part of the request. Many AWS SDKs handle authentication automatically, but there are situations where developers need to create custom HTTP requests, use a service-specific API, or integrate with an endpoint that does not have a convenient SDK method.
In these cases, AWS Signature Version 4, commonly called SigV4, provides a way to authenticate HTTP requests using AWS credentials. The signature is calculated from parts of the request, including the HTTP method, URI, headers, and payload hash.
Implementing SigV4 manually can be error-prone. Small differences in URL encoding, header formatting, timestamps, or payload hashing can cause AWS to reject a request.
This article explains how SigV4 works, how to sign custom HTTP requests in .NET, and which practices help prevent authentication failures in production.
What Is AWS Signature Version 4?
AWS Signature Version 4, or SigV4, is a request-signing process used to authenticate requests to AWS services. It uses cryptographic signing to demonstrate that a request was created using valid AWS credentials and that the signed parts of the request have not changed.
A SigV4 signature is calculated using several elements:
HTTP method, such as GET or POST.
Canonical URI and query parameters.
Headers included in the signature.
A hash of the request payload.
Request timestamp.
AWS service name and region.
AWS credentials used to calculate the signature.
The resulting signature is included in the HTTP Authorization header.
For example, an IAM-authorized API Gateway endpoint may require a SigV4-signed request. Sending a normal HTTP request without the required authentication information can result in an authorization error.
When Should You Use a Standalone SigV4 Signer?
The AWS SDK for .NET provides service-specific clients that automatically handle request signing. These clients should generally be your first choice when they support the operation you need.
A standalone signer is useful when you need to create custom HTTP requests and no suitable generated SDK operation is available.
Approach | Best use case | Main consideration |
|---|
AWS service client | Calling a supported AWS API operation | Simplifies authentication, serialization, and service-specific handling |
Standalone SigV4 signer | Signing a custom HTTP request | You manage the HTTP request and response |
SigV4 signing handler | Automatically signing requests sent through HttpClient | Requires careful handler configuration for retries and redirects |
Presigned URL | Allowing temporary access to a supported resource or operation | Anyone possessing the URL may be able to use it within its validity and permissions |
The AWS SDK for .NET includes a public standalone signer in AWSSDK.Core version 4.0.101.0 and later. It supports header-based signing and presigned URLs without requiring you to implement the SigV4 algorithm yourself.
Setting Up SigV4 Signing in .NET
For this example, you will use C# with HttpClient to call an IAM-authorized AWS Security Token Service endpoint.
The example uses the GetCallerIdentity operation, which returns information about the AWS identity making the request.
Step 1: Install the AWS SDK Core Package
Create a console application:
dotnet new console -n SigV4Demo
cd SigV4Demo
Install the AWS SDK Core package:
dotnet add package AWSSDK.Core --version 4.0.101.0
If your project already references a compatible version of AWSSDK.Core, verify the installed version before adding another package reference.
Step 2: Configure AWS Credentials
The signer needs AWS credentials to calculate the signature.
For local development, you can configure credentials through the AWS CLI or another supported AWS credential provider.
For example, an existing AWS CLI profile can be configured using:
aws configure --profile developer
The AWS SDK credential resolution chain can then obtain credentials from supported sources, including profiles and environment-based configuration.
For production applications, prefer IAM roles and temporary credentials where available. Applications running on AWS services can often obtain credentials through their assigned execution or instance role.
Avoid placing access keys directly in source code or committing credential files to a repository.
Signing and Sending a Custom HTTP Request
The following example creates a request, signs it, applies the generated authentication headers, and sends it using HttpClient.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Amazon;
using Amazon.Runtime.Credentials;
using Amazon.Runtime.Signing;
public class Program
{
public static async Task Main()
{
var requestUri = new Uri(
"https://sts.us-east-1.amazonaws.com/" +
"?Action=GetCallerIdentity" +
"&Version=2011-06-15");
var signingRequest = new AWSSigningRequest
{
HttpMethod = HttpMethod.Get,
RequestUri = requestUri
};
var signingParameters = new AWSSigV4Parameters
{
Credentials =
DefaultAWSCredentialsIdentityResolver.GetCredentials(),
Region = RegionEndpoint.USEast1,
Service = "sts"
};
var signingResult = await AWSSigV4Signer.SignAsync(
signingRequest,
signingParameters,
default);
using var httpClient = new HttpClient();
using var httpRequest = new HttpRequestMessage(
HttpMethod.Get,
requestUri);
foreach (var header in signingResult.Headers)
{
httpRequest.Headers.TryAddWithoutValidation(
header.Key,
header.Value);
}
using var response = await httpClient.SendAsync(httpRequest);
var responseBody = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Console.WriteLine(responseBody);
}
}
This example uses the standalone signer API available in recent versions of the AWS SDK for .NET. AWS
Understanding the Important Parts
The AWSSigningRequest object describes the HTTP request that needs to be signed. It contains the HTTP method and the complete request URI, including the query string.
The AWSSigV4Parameters object identifies the credentials, AWS region, and service being called.
In this example:
RegionEndpoint.USEast1 identifies the AWS region.
Service = "sts" identifies the Security Token Service signing name.
DefaultAWSCredentialsIdentityResolver.GetCredentials() resolves credentials through the AWS SDK's credential-resolution mechanism.
AWSSigV4Signer.SignAsync() calculates the signature and returns the headers to apply to the outbound request.
The signing operation does not send the HTTP request. That responsibility remains with HttpClient.
This separation is useful when an application needs to control its HTTP transport, inspect responses, or integrate signing into an existing request pipeline.
The endpoint, region, and service name must match the operation being called. Using an incorrect service name or region can produce a signature mismatch.
Signing POST Requests With a JSON Payload
Custom AWS HTTP requests frequently contain JSON data. In these cases, the payload must be handled consistently during signing and transmission.
Consider an IAM-authorized API Gateway endpoint that accepts a JSON request.
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Amazon;
using Amazon.Runtime.Credentials;
using Amazon.Runtime.Signing;
public class ApiClient
{
public static async Task SendRequestAsync()
{
var requestUri = new Uri(
"https://example.execute-api.us-east-1.amazonaws.com/prod/items");
var json = """
{
"name": "Keyboard",
"quantity": 2
}
""";
var payload = Encoding.UTF8.GetBytes(json);
var signingRequest = new AWSSigningRequest
{
HttpMethod = HttpMethod.Post,
RequestUri = requestUri,
Content = payload
};
var parameters = new AWSSigV4Parameters
{
Credentials =
DefaultAWSCredentialsIdentityResolver.GetCredentials(),
Region = RegionEndpoint.USEast1,
Service = "execute-api"
};
var signingResult = await AWSSigV4Signer.SignAsync(
signingRequest,
parameters,
default);
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage(
HttpMethod.Post,
requestUri);
request.Content = new ByteArrayContent(payload);
request.Content.Headers.ContentType =
new System.Net.Http.Headers.MediaTypeHeaderValue(
"application/json");
foreach (var header in signingResult.Headers)
{
request.Headers.TryAddWithoutValidation(
header.Key,
header.Value);
}
using var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine("Request completed successfully.");
}
}
Replace the example endpoint with your actual API Gateway endpoint and ensure the IAM identity has permission to invoke it.
The Content property supplies the payload used during signing. The same payload bytes are then sent through HttpClient.
Using the same bytes is important because changing the payload after signing can cause the request to fail signature validation.
The execute-api service name is appropriate for API Gateway requests that use SigV4 authentication. Other AWS services require their respective signing service names.
Common SigV4 Errors and Troubleshooting
SigV4 failures often result from differences between the request that was signed and the request that AWS received.
Error or symptom | Possible cause | Recommended fix |
|---|
SignatureDoesNotMatch
| Request URI, payload, or signed headers changed | Verify the exact URI, headers, and payload |
InvalidSignatureException
| Incorrect signing configuration | Check the service name, region, and credential source |
AccessDeniedException or HTTP 403
| Missing IAM permissions or an authorization restriction | Review the identity policy and resource policy |
Expired-token error | Temporary credentials have expired | Refresh credentials through the configured provider |
Request rejected after a redirect | The redirected request was not signed for its new destination | Handle redirects explicitly and sign each destination |
Request rejected after a delayed retry | The original signature was reused or became too old | Generate a fresh signature for each attempt |
Check the AWS Region and Service Name
The region and service name are inputs to the signing process.
For example, an API Gateway request commonly uses execute-api, while an STS request uses sts.
If the endpoint points to one region but the signer uses another, AWS may reject the request.
Always derive the signing configuration from the actual service endpoint and operation.
Check the Request After Signing
Avoid modifying the URI, query string, signed headers, or payload after calculating the signature.
If a request needs to be changed, create or update the request and sign it again.
Be especially careful with HTTP middleware that changes URLs, adds headers, or retries requests after signing.
Handle Temporary Credentials Correctly
Temporary AWS credentials include a session token in addition to the access key ID and secret access key.
The signing implementation must use credentials that include the required session information. Using expired credentials or failing to include the session token can cause authentication failures.
Use a supported credential provider instead of manually assembling credential values whenever possible.
Best Practices for Production Applications
Use the AWS SDK Whenever Possible
If a generated AWS service client supports your operation, use it instead of creating and signing raw HTTP requests.
Service clients generally provide service-specific request models, response handling, retry behavior, and authentication integration.
Use the standalone signer when a custom HTTP integration genuinely requires it.
Reuse HttpClient
Avoid creating a new HttpClient for every request in a high-volume application.
Reuse a client or use IHttpClientFactory in ASP.NET Core applications. This helps manage connection lifetimes and avoids unnecessary socket consumption.
Sign Every Retry Separately
A retry must not blindly reuse a previously signed request.
SigV4 signatures include time-sensitive information, and the signed request must match the request being transmitted.
Configure retry handling so that every attempt passes through the signing process again.
Handle Redirects Carefully
Automatic redirects can cause a signed request to be sent to a different URI without recalculating the signature.
For signed HTTP clients, disable automatic redirects in the underlying transport and handle redirects explicitly when required. Validate the destination before sending credentials or signing a request for it.
Protect Credentials and Logs
Never log secret access keys, session tokens, or complete Authorization headers.
Log useful diagnostic information instead, such as the HTTP status code, AWS request identifier when available, target service, and a sanitized error message.
Use HTTPS
Always use HTTPS for AWS service requests. Transport encryption protects data in transit, while SigV4 authenticates the signed request.
These protections address different concerns and should be used together.
Advantages and Disadvantages of the Standalone SigV4 Signer
The standalone signer makes it easier to authenticate custom AWS HTTP requests without implementing the cryptographic signing algorithm manually.
Its main advantages include support for custom request workflows, integration with HttpClient, and the ability to generate presigned URLs.
However, it does not replace a service client. Developers remain responsible for request construction, response processing, retries, endpoint handling, and application-specific error recovery.
The signing process also requires careful attention to request consistency, timestamps, payloads, and credentials. An incorrect configuration can cause failures that are difficult to diagnose without good logging.
Summary
AWS Signature Version 4 allows .NET applications to authenticate custom HTTP requests to supported AWS endpoints. The standalone signer in AWSSDK.Core provides a public API for calculating signatures without requiring developers to implement the SigV4 algorithm themselves.
To use it correctly, construct the request first, configure the appropriate credentials, region, and service name, calculate the signature, and apply the returned headers before sending the request.
For production applications, prioritize supported AWS service clients when available. When custom HTTP requests are necessary, use HTTPS, preserve the signed request, refresh credentials correctly, and ensure every retry is signed independently.
Join the conversation! Your thoughts help the community grow.