Skip to content

Latest commit

 

History

History
176 lines (131 loc) · 6.88 KB

README.md

File metadata and controls

176 lines (131 loc) · 6.88 KB

aws-sigv4-sign

A small library for signing HTTP requests with AWS Signature Version 4 (SigV4) authentication, built with the official AWS SDK.

Tip

If you are using the fetch API, consider using the aws-sigv4-fetch package to automatically sign requests.

Install

npm install --save aws-sigv4-sign

ESM and CommonJS

This package ships with ES Module and CommonJS support. That means you can import or require the package in your project depending on your module format.

// ESM
import { signRequest } from 'aws-sigv4-sign';

// CommonJS
const { signRequest } = require('aws-sigv4-sign');

Usage

This package exports a signRequest function that returns a Request object with signed headers for AWS Signature V4 (SigV4) authentication. The function is overloaded with the same signature as the fetch API and an optional options parameter.

import { signRequest, SignRequestOptions } from 'aws-sigv4-sign';

const options: SignRequestOptions = {
  service: 'lambda',         // required
  region: 'eu-west-1',       // optional (defaults to 'us-east-1')
  credentials: {             // optional (defaults to credentials from environment)
    accessKeyId: '...',
    secretAccessKey: '...',
  }
};

const url = 'https://mylambda.lambda-url.eu-west-1.on.aws/';

// signRequest(input: string, options: SignRequestOptions)
const signedRequest = await signRequest(url, options);

// signRequest(input: URL, options: SignRequestOptions)
const signedRequest = await signRequest(new URL(url), options);

// signRequest(input: Request, options: SignRequestOptions)
const signedRequest = await signRequest(new Request(url), options);

// signRequest(input: string, init?: RequestInit, options: SignRequestOptions)
const signedRequest = await signRequest(url,
  {
    method: 'POST',
    body: JSON.stringify({ a: 1 }),
    headers: { 'Content-Type': 'application/json' }
  },
  options
);

The returned Request object contains the signed authorization headers with the following keys: authorization, host, x-amz-date, x-amz-content-sha256, x-amz-security-token (optional).

const signedRequest = await signRequest(url, options);

// Fetch the signed request
const response = await fetch(signedRequest);

// Log the signed headers from the request
console.log(signedRequest.headers.get('authorization')); // AWS4-HMAC-SHA256 Credential=.../20250101/us-east-1/lambda/aws4_request, SignedHeaders=host;x-amz-date;x-amz-content-sha256;x-amz-security-token, Signature=...
console.log(signedRequest.headers.get('host')); // mylambda.lambda-url.eu-west-1.on.aws
console.log(signedRequest.headers.get('x-amz-date')); // 20250101T000000Z
console.log(signedRequest.headers.get('x-amz-content-sha256')); // ...
console.log(signedRequest.headers.get('x-amz-security-token')); // only if credentials include a session token

// Convert the signed headers to plain object
const headers = Object.fromEntries(signedRequest.headers.entries());
console.log(headers.authorization); // AWS4-HMAC-SHA256 Credential=.../20250101/us-east-1/lambda/aws4_request, SignedHeaders=host;x-amz-date;x-amz-content-sha256;x-amz-security-token, Signature=...

The headers is a Headers object and can be converted to plain object for use with other HTTP libraries.

Options

The signRequest function accepts the following options:

Parameter Type Default Description
service string Required The service is required and must match the AWS service you are signing requests for. If it doesn't match, the request will fail with an error like: Credential should be scoped to correct service: 'service'.
region string us-east-1 The region is optional and defaults to us-east-1 if not provided. Some services like IAM are global and don't require a region.
credentials object Read from environment The credentials is optional. If not provided, the credentials will be retrieved from the environment by the package @aws-sdk/credential-provider-node.

Examples

The following examples show how to use the signed request with different HTTP libraries.

import { signRequest } from "aws-sigv4-sign";

const signedRequest = await signRequest('https://mylambda.lambda-url.eu-west-1.on.aws/', { service: 'lambda', region: 'eu-west-1' });
const response = await fetch(signedRequest);
import axios from "axios";
import { signRequest } from "aws-sigv4-sign";

const signedRequest = await signRequest('https://mylambda.lambda-url.eu-west-1.on.aws/', { service: 'lambda', region: 'eu-west-1' });
const headers = Object.fromEntries(signedRequest.headers.entries());
const response = await axios(signedRequest.url, { headers });
import { signRequest } from "aws-sigv4-sign";
import got from "got";

const signedRequest = await signRequest('https://mylambda.lambda-url.eu-west-1.on.aws/', { service: 'lambda', region: 'eu-west-1' });
const headers = Object.fromEntries(signedRequest.headers.entries());
const response = await got(signedRequest.url, { headers });
import { signRequest } from "aws-sigv4-sign";
import ky from "ky";

const signedRequest = await signRequest('https://mylambda.lambda-url.eu-west-1.on.aws/', { service: 'lambda', region: 'eu-west-1' });
const headers = Object.fromEntries(signedRequest.headers.entries());
const response = await ky.get(signedRequest.url, { headers });
import { signRequest } from "aws-sigv4-sign";
import { request } from "node:https";

const signedRequest = await signRequest('https://mylambda.lambda-url.eu-west-1.on.aws/', { service: 'lambda', region: 'eu-west-1' });
const headers = Object.fromEntries(signedRequest.headers.entries());
const body = "";
const response = new Promise((resolve, reject) => {
  const req = request(signedRequest.url, { headers }, (res) => {
    let data = "";

    res.on("data", (chunk) => {
      data += chunk;
    });

    res.on("end", () =>
      resolve({
        status: res.statusCode ?? 0,
        statusText: res.statusMessage,
        data,
      }),
    );
  });

  req.on("error", reject);

  if (body) {
    req.write(body);
  }

  req.end();
});

License

MIT