Skip to content

Commit

Permalink
feat: support for X-Amz-Content-Sha256 (#1621)
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock authored and jamesmbourne committed Feb 23, 2025
1 parent 76a083e commit 9b66f0c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@ const interceptor = aws4Interceptor({
});
```

Newer services, such as [Amazon OpenSearch Serverless](https://aws.amazon.com/opensearch-service/features/serverless/), require a content SHA. Pass `addContentSha` to `options` to enable adding an `X-Amz-Content-Sha256` header to the request.

```typescript
const interceptor = aws4Interceptor({
options: {
region: "eu-west-2",
service: "aoss",
addContentSha: true,
},
credentials: {
accessKeyId: "",
secretAccessKey: "",
},
});
```

# Migration to v3

The interface for options changed in v3. You should now pass a single object with configuration.
Expand Down
56 changes: 56 additions & 0 deletions src/interceptor.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sign } from "aws4";

import axios, {
AxiosHeaders,
AxiosRequestHeaders,
Expand Down Expand Up @@ -38,6 +39,7 @@ beforeEach(() => {
(sign as jest.Mock).mockReset();
});


describe("interceptor", () => {
it("signs GET requests", async () => {
// Arrange
Expand Down Expand Up @@ -215,6 +217,35 @@ describe("interceptor", () => {
},
undefined,
);

expect(request.headers['X-Amz-Content-Sha256']).toBeUndefined()
});

it("adds X-Amz-Content-Sha256 for a string payload", async () => {
// Arrange
const data = "foobar";
const request: InternalAxiosRequestConfig = {
method: "POST",
url: "https://example.com/foobar",
data,
headers: getDefaultHeaders(),
transformRequest: getDefaultTransformRequest(),
};

const interceptor = aws4Interceptor({
options: {
region: "local",
service: "execute-api",
addContentSha: true
},
instance: axios,
});

// Act
await interceptor(request);

// Assert
expect(request.headers['X-Amz-Content-Sha256']).toEqual('c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2')
});

it("passes Content-Type header to be signed", async () => {
Expand Down Expand Up @@ -333,6 +364,31 @@ describe("interceptor", () => {
undefined,
);
});

it("passes option to add a content SHA", async () => {
// Arrange
const request: InternalAxiosRequestConfig = {
method: "GET",
url: "https://example.com/foobar",
headers: getDefaultHeaders(),
transformRequest: getDefaultTransformRequest(),
};

const interceptor = aws4Interceptor({
instance: axios,
options: {
region: "local",
service: "execute-api",
addContentSha: true,
},
});

// Act
await interceptor(request);

// Assert
expect(request.headers['X-Amz-Content-Sha256']).toEqual('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
});
});

describe("credentials", () => {
Expand Down
9 changes: 9 additions & 0 deletions src/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CredentialsProvider } from ".";
import { AssumeRoleCredentialsProvider } from "./credentials/assumeRoleCredentialsProvider";
import { isCredentialsProvider } from "./credentials/isCredentialsProvider";
import { SimpleCredentialsProvider } from "./credentials/simpleCredentialsProvider";
import { createHash } from "crypto";

export interface InterceptorOptions {
/**
Expand All @@ -27,6 +28,10 @@ export interface InterceptorOptions {
* Whether to sign query instead of adding Authorization header. Default to false.
*/
signQuery?: boolean;
/**
* Whether to add a X-Amz-Content-Sha256 header.
*/
addContentSha?: boolean;
/**
* ARN of the IAM Role to be assumed to get the credentials from.
* The credentials will be cached and automatically refreshed as needed.
Expand Down Expand Up @@ -198,6 +203,10 @@ export const aws4Interceptor = <D = any>({
}
}

if (options?.addContentSha) {
config.headers.set('X-Amz-Content-Sha256', createHash('sha256').update(transformedData ?? '', 'utf8').digest('hex'))
}

return config;
};
};
Expand Down

0 comments on commit 9b66f0c

Please sign in to comment.