Automatically Sign AWS Requests with Signature V4
// #aws#fetch#javascript#signaturev4#typescript // 2 comments
In a previous article, I explored the challenges of using Lambda Function URLs with IAM authorization and CloudFront custom domains. A key aspect of this setup involves signing HTTP requests with AWS Signature Version 4 (SigV4) to authenticate with IAM.
While the AWS SDK provides utilities for SigV4 signing, the process can be somewhat cumbersome, especially when working with the barebone functions like fetch
instead of SDKs. To simplify this process, I've created the aws-sigv4-fetch
package, which automatically signs fetch requests with SigV4 for a given AWS service and region.
What is AWS Signature Version 4?
AWS Signature Version 4 (SigV4) is a process for adding authentication information to AWS API requests sent over HTTP. For security reasons, most requests to AWS must be signed with an access key, which consists of an access key ID and a secret access key (your AWS credentials).
The SigV4 signing process involves creating a canonical request based on the HTTP request details, calculating a signature using your AWS credentials, and adding this signature to the request as an Authorization
header. AWS then replicates this process and verifies the signature, granting or denying access accordingly.
For a more detailed explanation of SigV4, refer to my previous article or the AWS documentation.
Sign All Requests
The aws-sigv4-fetch
package aims to simplify the SigV4 signing process for modern JavaScript applications. It exports a single function, createSignedFetcher
, which returns a fetch
function that automatically signs HTTP requests with SigV4 for the specified AWS service and region.
Here's an example usage:
import { createSignedFetcher } from 'aws-sigv4-fetch'; const signedFetch = createSignedFetcher({ service: 'execute-api', region: 'eu-west-1' }); const url = '<https://restapi.execute-api.eu-west-1.amazonaws.com/foo/bar>'; const response = await signedFetch(url); const data = await response.json();
In this example, we create a signedFetch
function that automatically signs requests to API Gateway in the eu-west-1
region. We can then use this function like a regular fetch
, passing in the URL and request options. The aws-sigv4-fetch
package will handle the SigV4 signing process behind the scenes, adding the necessary Authorization
header to the request.
The createSignedFetcher
function accepts an optional fetch
argument, allowing you to pass in a custom fetch
implementation (e.g., a polyfill like cross-fetch
). If no fetch
is provided, it defaults to the native fetch
function which is available in Node.js since v18.
ESM and CommonJS Support
The aws-sigv4-fetch
package is available on npm and can be installed with your preferred package manager:
npm install aws-sigv4-fetch
The package supports both ES Modules and CommonJS, so you can import
or require
it as needed:
// ESM import { createSignedFetcher } from 'aws-sigv4-fetch'; // CommonJS const { createSignedFetcher } = require('aws-sigv4-fetch'); const signedFetch = createSignedFetcher({ service: 'appsync', region: 'eu-west-1' });
Integration with GraphQL Libraries
The aws-sigv4-fetch
package can be integrated into GraphQL libraries like graphql-request
. For example, you can pass the signedFetch
function as the custom fetch
option:
import { createSignedFetcher } from 'aws-sigv4-fetch'; import { GraphQLClient } from 'graphql-request'; const signedFetch = createSignedFetcher({ service: 'appsync', region: 'eu-west-1' }); const client = new GraphQLClient('<https://graphqlapi.appsync-api.eu-west-1.amazonaws.com/graphql>', { fetch: signedFetch, }); const result = await client.request(query, variables);
With this setup, all GraphQL requests made through the client
will be automatically signed with SigV4.
Contributions
I am in the process of adding E2E tests for AWS services. So far only API Gateway and IAM are covered by tests with real resources. If you are using a specific AWS service and want to make sure that aws-sigv4-fetch
always works with that service, I would greatly appreciate your contribution. Of course, feedback and improvements are always welcome.