aws-requests-auth
aws-requests-auth is a small requests authentication adapter that calculates AWS Signature Version 4 headers for an outgoing Python HTTP request. You give it the AWS host, region, service name, and credentials, then pass the resulting object through requests' auth parameter. Its original focus was Amazon Elasticsearch Service, now called Amazon OpenSearch Service, but the signer can work with other AWS HTTPS endpoints that accept header-based SigV4 authentication.
Keep it only for a tested legacy requests integration. New AWS code should generally use a service client or botocore signer because this package's examples and release cadence are far behind current AWS practice.
Use it if
- You maintain an existing requests-based integration that already uses AWSRequestsAuth and only needs SigV4 header signing
- You call an AWS-style endpoint that has no suitable boto3 client and need to retain the requests API
- You need a tiny adapter whose signing code is short enough to audit locally
- You can pin and test the package because the upstream release line has been quiet for years
- You are starting a new AWS integration: botocore already supplies the official credential chain and SigV4 signing primitives, while this package last released 0.4.3 in May 2020
- You want maintained OpenSearch examples: the README still demonstrates the old Elasticsearch service name, Python 2 print syntax, port 80, and an obsolete RequestsHttpConnection integration
- You need presigned URLs, streaming-body signing, SigV4a, or service-specific behavior; this class only creates header-based SigV4 signatures for a prepared requests request
- Your query strings contain tricky encoding cases: the source explicitly assumes parameters are already URL-encoded, sorts raw query fragments, and warns that incorrect encoding causes signature failures
- You expect automatic credentials without another dependency: BotoAWSRequestsAuth imports botocore, but botocore is optional and is not installed by aws-requests-auth
Setup reality
The base install is only pip install aws-requests-auth plus its requests dependency, but usable AWS authentication still takes care. AWSRequestsAuth requires an access key, secret key, exact hostname, region, and AWS service identifier. Temporary STS credentials also require aws_token; leaving the session token out produces a signature that AWS rejects. Do not paste long-lived keys into source. The BotoAWSRequestsAuth helper is safer because it asks botocore's credential provider chain for environment, shared-config, container, or instance-role credentials and refreshes them before signing, but botocore is not declared as a required dependency, so install it separately. The signer uses the hostname you pass rather than deriving it from the request URL, which makes custom ports, proxies, and mismatched endpoints easy to get wrong. Query parameters must already have the encoding AWS expects. Use HTTPS even though the old README examples show HTTP. There is no timeout, retry, connection pooling, or response handling here; those remain requests configuration. Pin the old 0.4.3 release and keep integration tests against the real AWS service because the repository has not shipped a release since 2020 and its last code push was in 2023.
Patterns
Sign a GET requestsign-get-request
import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth
host = "search-example.us-east-1.es.amazonaws.com"
auth = AWSRequestsAuth(
aws_access_key=access_key,
aws_secret_access_key=secret_key,
aws_host=host,
aws_region="us-east-1",
aws_service="es",
)
response = requests.get(f"https://{host}/_cluster/health", auth=auth, timeout=10)
response.raise_for_status()aws_host must match the host that AWS validates, and requests still needs an explicit timeout.
Sign a JSON POSTsign-post-json
response = requests.post(
f"https://{host}/my-index/_search",
json={"query": {"match_all": {}}},
auth=auth,
timeout=30,
)
response.raise_for_status()The signer hashes the prepared request body, so pass json or data when making the request rather than changing the body afterward.
Sign with temporary STS credentialsuse-session-token
auth = AWSRequestsAuth(
aws_access_key=credentials["AccessKeyId"],
aws_secret_access_key=credentials["SecretAccessKey"],
aws_token=credentials["SessionToken"],
aws_host=host,
aws_region="us-east-1",
aws_service="execute-api",
)All three temporary credential values belong together; omitting aws_token makes the signed request invalid.
Use botocore credential discoverydiscover-credentials
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
auth = BotoAWSRequestsAuth(
aws_host=host,
aws_region="us-east-1",
aws_service="execute-api",
)Install botocore separately. This helper resolves and refreshes credentials when requests are signed.
Call an IAM-protected API Gateway routecall-api-gateway
host = "abc123.execute-api.us-east-1.amazonaws.com"
auth = BotoAWSRequestsAuth(host, "us-east-1", "execute-api")
response = requests.post(
f"https://{host}/prod/jobs",
json={"job": "reindex"},
auth=auth,
timeout=15,
)The service identifier for API Gateway is execute-api, not apigateway.
Reuse connections with a requests sessionreuse-http-session
session = requests.Session()
session.auth = auth
session.headers.update({"Accept": "application/json"})
for index in ("orders", "customers"):
r = session.get(f"https://{host}/{index}/_count", timeout=10)
r.raise_for_status()A Session reuses connections, but every prepared request is signed independently with its current body and URL.
Send already encoded query parameterssend-query-parameters
from urllib.parse import urlencode
query = urlencode({"Action": "GetCallerIdentity", "Version": "2011-06-15"}, quote_via=__import__("urllib.parse").parse.quote)
r = requests.get(f"https://{host}/?{query}", auth=auth, timeout=10)The implementation assumes the URL query is already encoded and sorts its raw key-value fragments during canonicalization.
Prepare and inspect signing headersinspect-signed-request
request = requests.Request("GET", f"https://{host}/")
prepared = request.prepare()
auth(prepared)
print(prepared.headers["Authorization"])
print(prepared.headers["x-amz-date"])Useful in tests, but do not log full Authorization headers in production because they contain credential identifiers and signatures.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| requests-aws4auth | PyPI | You want a requests-compatible SigV4 adapter with newer service examples and active release history |
| botocore | PyPI | You want AWS-maintained credential discovery, request signing, refresh behavior, and service models |
| httpx-auth | PyPI | Your application uses HTTPX and needs composable authentication rather than a requests-only hook |