Skip to content

Latest commit

 

History

History
184 lines (138 loc) · 7.72 KB

README.md

File metadata and controls

184 lines (138 loc) · 7.72 KB

CI npm npm

aws-sigv4-fetch

A lightweight wrapper around the fetch API that automatically signs HTTP requests with AWS Signature Version 4 (SigV4) authentication. Built on the official AWS SDK for JS v3.

Signature Version 4

Signature Version 4 (SigV4) is the process to add authentication information to AWS API requests sent by HTTP. For security, most requests to AWS must be signed with an access key. The access key consists of an access key ID and secret access key, which are commonly referred to as your security credentials

AWS documentation on Signature Version 4 signing process

Install

npm install --save aws-sigv4-fetch

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 { createSignedFetcher } from 'aws-sigv4-fetch';

// CommonJS
const { createSignedFetcher } = require('aws-sigv4-fetch');

Usage

This package exports a function createSignedFetcher that returns a fetch function to automatically sign HTTP requests with AWS Signature V4 for the given AWS service and region. The returned signedFetch function accepts the same arguments as the default fetch function.

import { createSignedFetcher } from 'aws-sigv4-fetch';

const signedFetch = createSignedFetcher({ service: 's3', region: 'eu-west-1' });

// signedFetch(input: string)
const response = await signedFetch('https://s3.eu-west-1.amazonaws.com/my-bucket/my-key.json');

// signedFetch(input: URL)
const response = await signedFetch(new URL('https://s3.eu-west-1.amazonaws.com/my-bucket/my-key.json'));

// signedFetch(input: Request)
const response = await signedFetch(new Request('https://s3.eu-west-1.amazonaws.com/my-bucket/my-key.json'));

// signedFetch(input: string, init?: RequestInit)
const response = await signedFetch('https://s3.eu-west-1.amazonaws.com/my-bucket/my-key.json', {
  method: 'POST',
  body: JSON.stringify({ a: 1 }),
  headers: { 'Content-Type': 'application/json' }
});

API

The createSignedFetcher(options: SignedFetcherOptions) function accepts the following options:

type SignedFetcherOptions = {
  service: string;
  region?: string;
  credentials?: AwsCredentialIdentity;
  fetch?: typeof fetch;
};

Service

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

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

The credentials is optional. If not provided, the credentials will be retrieved from the environment by the package @aws-sdk/credential-provider-node.

import { createSignedFetcher } from 'aws-sigv4-fetch';

// credentials will be retrieved from the environment
const signedFetch = createSignedFetcher({ service: 's3', region: 'eu-west-1' });

// credentials will be passed directly to the function
const signedFetch = createSignedFetcher({ service: 's3', region: 'eu-west-1', credentials: { accessKeyId: '...', secretAccessKey: '...' } });

Fetch

The fetch function is optional. If not provided, the fetch function from the environment will be used. Native fetch is supported in Node.js >= v18. If you are running in an environment where native fetch is not available, the fetch function must be polyfilled or provided as an argument to createSignedFetcher. This allows to use the same fetch function that is already used in your application. There are several ways to do this:

Native fetch

If native fetch is available, you don't have to pass it as argument to createSignedFetcher.

import { createSignedFetcher } from 'aws-sigv4-fetch';

// native fetch is available and doesn't have to be passed as argument
const signedFetch = createSignedFetcher({ service: 'iam', region: 'eu-west-1' });

Polyfill fetch

Install a fetch package like cross-fetch and import it as polyfill. The fetch function will be available globally after importing the polyfill.

import 'cross-fetch/polyfill';
import { createSignedFetcher } from 'aws-sigv4-fetch';

// fetch was imported globally and doesn't have to be passed as argument
const signedFetch = createSignedFetcher({ service: 'iam', region: 'eu-west-1' });

Pass fetch as an argument

Install a fetch package like cross-fetch and import it as ponyfill. The fetch function will be available locally after importing the ponyfill. Pass the fetch function as an argument to createSignedFetcher:

import fetch from 'cross-fetch';
import { createSignedFetcher } from 'aws-sigv4-fetch';

// fetch was imported locally and must be passed as argument
const signedFetch = createSignedFetcher({ service: 'iam', region: 'eu-west-1', fetch });

Examples

AWS

Here are some examples of common AWS services.

// API Gateway
const signedFetch = createSignedFetcher({ service: 'execute-api', region: 'eu-west-1' });
const response = await signedFetch('https://myapi.execute-api.eu-west-1.amazonaws.com/my-stage/my-resource');

// Lambda Function URL
const signedFetch = createSignedFetcher({ service: 'lambda', region: 'eu-west-1' });
const response = await signedFetch(new URL('https://mylambda.lambda-url.eu-west-1.on.aws/'));

// AppSync
const signedFetch = createSignedFetcher({ service: 'appsync', region: 'eu-west-1' });
const response = await signedFetch('https://mygraphqlapi.appsync-api.eu-west-1.amazonaws.com/graphql', {
  method: 'POST',
  body: JSON.stringify({ a: 1 }),
  headers: {'Content-Type': 'application/json'}
});

Automatically sign GraphQL Requests with graphql-request

If you are using graphql-request as GraphQL library, you can easily sign all HTTP requests. The library has fetch option to pass a custom fetch method:

import { createSignedFetcher } from 'aws-sigv4-fetch';
import { GraphQLClient } from 'graphql-request';

const query = `
  mutation CreateItem($input: CreateItemInput!) {
    createItem(input: $input) {
      id
      createdAt
      updatedAt
      name
    }
  }
`;

const variables = {
  input: {
    name,
  },
};

const client = new GraphQLClient('https://mygraphqlapi.appsync-api.eu-west-1.amazonaws.com/graphql', {
  fetch: createSignedFetcher({ service: 'appsync', region: 'eu-west-1' }),
});

const result = await client.request(query, variables);

Resources

License

MIT