From 240f587ddca753bfbddc222d1bca18639d436049 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 21 May 2025 16:15:47 +0000 Subject: [PATCH 1/5] chore(token-providers): add provider to retrieve token from environment variable --- .../src/submodules/httpAuthSchemes/index.ts | 1 + packages/token-providers/package.json | 1 + .../src/fromEnvBearerToken.spec.ts | 46 +++++++++++++++++++ .../token-providers/src/fromEnvBearerToken.ts | 34 ++++++++++++++ packages/token-providers/src/index.ts | 1 + yarn.lock | 1 + 6 files changed, 84 insertions(+) create mode 100644 packages/token-providers/src/fromEnvBearerToken.spec.ts create mode 100644 packages/token-providers/src/fromEnvBearerToken.ts diff --git a/packages/core/src/submodules/httpAuthSchemes/index.ts b/packages/core/src/submodules/httpAuthSchemes/index.ts index 29d0c3bdf9f8..3927741ab30a 100644 --- a/packages/core/src/submodules/httpAuthSchemes/index.ts +++ b/packages/core/src/submodules/httpAuthSchemes/index.ts @@ -1 +1,2 @@ export * from "./aws_sdk"; +export * from "./utils/getBearerTokenEnvKey"; diff --git a/packages/token-providers/package.json b/packages/token-providers/package.json index f554a01b80ce..f8420d643a13 100644 --- a/packages/token-providers/package.json +++ b/packages/token-providers/package.json @@ -27,6 +27,7 @@ }, "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "*", "@aws-sdk/nested-clients": "*", "@aws-sdk/types": "*", "@smithy/property-provider": "^4.0.2", diff --git a/packages/token-providers/src/fromEnvBearerToken.spec.ts b/packages/token-providers/src/fromEnvBearerToken.spec.ts new file mode 100644 index 000000000000..f2dde67fafe5 --- /dev/null +++ b/packages/token-providers/src/fromEnvBearerToken.spec.ts @@ -0,0 +1,46 @@ +import { getBearerTokenEnvKey } from "@aws-sdk/core"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { fromEnvBearerToken } from "./fromEnvBearerToken"; + +vi.mock("@aws-sdk/core"); + +describe("fromEnvBearerToken", () => { + const originalEnv = process.env; + const mockInit = { signingName: "signing name" }; + const mockBearerTokenEnvKey = "AWS_BEARER_TOKEN_SIGNING_NAME"; + + beforeEach(() => { + process.env = { ...originalEnv }; + vi.mocked(getBearerTokenEnvKey).mockReturnValue(mockBearerTokenEnvKey); + }); + + afterEach(() => { + process.env = originalEnv; + vi.clearAllMocks(); + }); + + describe("throws error", () => { + it("when signingName is not passed", async () => { + await expect(fromEnvBearerToken()()).rejects.toThrow( + "Please pass 'signingName' to compute environment variable key" + ); + expect(getBearerTokenEnvKey).not.toHaveBeenCalled(); + }); + + it("when token is not present in environment variable", async () => { + await expect(fromEnvBearerToken(mockInit)()).rejects.toThrow( + `Token not present in '${mockBearerTokenEnvKey}' environment variable` + ); + expect(getBearerTokenEnvKey).toHaveBeenCalledWith(mockInit.signingName); + }); + }); + + it("returns token from environment variable", async () => { + const mockBearerToken = "mock-bearer-token"; + process.env[mockBearerTokenEnvKey] = mockBearerToken; + const token = await fromEnvBearerToken(mockInit)(); + expect(token).toEqual({ token: mockBearerToken }); + expect(getBearerTokenEnvKey).toHaveBeenCalledWith(mockInit.signingName); + }); +}); diff --git a/packages/token-providers/src/fromEnvBearerToken.ts b/packages/token-providers/src/fromEnvBearerToken.ts new file mode 100644 index 000000000000..5594d65b8cfb --- /dev/null +++ b/packages/token-providers/src/fromEnvBearerToken.ts @@ -0,0 +1,34 @@ +import { getBearerTokenEnvKey } from "@aws-sdk/core"; +import type { CredentialProviderOptions, TokenIdentityProvider } from "@aws-sdk/types"; +import { TokenProviderError } from "@smithy/property-provider"; + +export interface FromEnvBearerTokenInit extends CredentialProviderOptions { + signingName?: string; +} + +/** + * Creates a TokenIdentityProvider that retrieves bearer token from environment variable + * + * @param options - Configuration options for the token provider + * @param options.logger - Optional logger for debug messages + * @param options.signingName - Service signing name used to determine environment variable key + * @returns TokenIdentityProvider that provides bearer token from environment variable + * + * @public + */ +export const fromEnvBearerToken = + ({ logger, signingName }: FromEnvBearerTokenInit = {}): TokenIdentityProvider => + async () => { + logger?.debug("@aws-sdk/token-providers - fromEnvBearerToken"); + + if (!signingName) { + throw new TokenProviderError("Please pass 'signingName' to compute environment variable key", { logger }); + } + + const bearerTokenKey = getBearerTokenEnvKey(signingName); + if (!(bearerTokenKey in process.env)) { + throw new TokenProviderError(`Token not present in '${bearerTokenKey}' environment variable`, { logger }); + } + + return { token: process.env[bearerTokenKey]! }; + }; diff --git a/packages/token-providers/src/index.ts b/packages/token-providers/src/index.ts index a0b176b4f272..7dc8d6a2997e 100644 --- a/packages/token-providers/src/index.ts +++ b/packages/token-providers/src/index.ts @@ -1,3 +1,4 @@ +export * from "./fromEnvBearerToken"; export * from "./fromSso"; export * from "./fromStatic"; export * from "./nodeProvider"; diff --git a/yarn.lock b/yarn.lock index ec0c05bcf904..b6302bae2a84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23675,6 +23675,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aws-sdk/token-providers@workspace:packages/token-providers" dependencies: + "@aws-sdk/core": "npm:*" "@aws-sdk/nested-clients": "npm:*" "@aws-sdk/types": "npm:*" "@smithy/property-provider": "npm:^4.0.2" From 181885bafca312c4ac4f217ff8157b4a3a0fcfa4 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 21 May 2025 10:25:33 -0700 Subject: [PATCH 2/5] chore: add public tag for FromEnvBearerTokenInit Co-authored-by: George Fu --- packages/token-providers/src/fromEnvBearerToken.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/token-providers/src/fromEnvBearerToken.ts b/packages/token-providers/src/fromEnvBearerToken.ts index 5594d65b8cfb..cdd2753c7194 100644 --- a/packages/token-providers/src/fromEnvBearerToken.ts +++ b/packages/token-providers/src/fromEnvBearerToken.ts @@ -2,6 +2,9 @@ import { getBearerTokenEnvKey } from "@aws-sdk/core"; import type { CredentialProviderOptions, TokenIdentityProvider } from "@aws-sdk/types"; import { TokenProviderError } from "@smithy/property-provider"; +/** + * @public + */ export interface FromEnvBearerTokenInit extends CredentialProviderOptions { signingName?: string; } From 387c0b30d220fd76bb00552d752e5131e81161f1 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 21 May 2025 17:05:57 -0700 Subject: [PATCH 3/5] fix: use optional chaining for logger.debug Co-authored-by: George Fu --- packages/token-providers/src/fromEnvBearerToken.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/token-providers/src/fromEnvBearerToken.ts b/packages/token-providers/src/fromEnvBearerToken.ts index cdd2753c7194..500289d5e560 100644 --- a/packages/token-providers/src/fromEnvBearerToken.ts +++ b/packages/token-providers/src/fromEnvBearerToken.ts @@ -22,7 +22,7 @@ export interface FromEnvBearerTokenInit extends CredentialProviderOptions { export const fromEnvBearerToken = ({ logger, signingName }: FromEnvBearerTokenInit = {}): TokenIdentityProvider => async () => { - logger?.debug("@aws-sdk/token-providers - fromEnvBearerToken"); + logger?.debug?.("@aws-sdk/token-providers - fromEnvBearerToken"); if (!signingName) { throw new TokenProviderError("Please pass 'signingName' to compute environment variable key", { logger }); From a8107db960945434c1f38bdac5b4a4d7a6dd08a0 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Thu, 22 May 2025 15:01:52 +0000 Subject: [PATCH 4/5] chore: change name from fromEnvBearerToken to fromEnvSigningName --- ...vBearerToken.spec.ts => fromEnvSigningName.spec.ts} | 10 +++++----- .../{fromEnvBearerToken.ts => fromEnvSigningName.ts} | 8 ++++---- packages/token-providers/src/index.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) rename packages/token-providers/src/{fromEnvBearerToken.spec.ts => fromEnvSigningName.spec.ts} (82%) rename packages/token-providers/src/{fromEnvBearerToken.ts => fromEnvSigningName.ts} (83%) diff --git a/packages/token-providers/src/fromEnvBearerToken.spec.ts b/packages/token-providers/src/fromEnvSigningName.spec.ts similarity index 82% rename from packages/token-providers/src/fromEnvBearerToken.spec.ts rename to packages/token-providers/src/fromEnvSigningName.spec.ts index f2dde67fafe5..f570dfedba78 100644 --- a/packages/token-providers/src/fromEnvBearerToken.spec.ts +++ b/packages/token-providers/src/fromEnvSigningName.spec.ts @@ -1,11 +1,11 @@ import { getBearerTokenEnvKey } from "@aws-sdk/core"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { fromEnvBearerToken } from "./fromEnvBearerToken"; +import { fromEnvSigningName } from "./fromEnvSigningName"; vi.mock("@aws-sdk/core"); -describe("fromEnvBearerToken", () => { +describe(fromEnvSigningName.name, () => { const originalEnv = process.env; const mockInit = { signingName: "signing name" }; const mockBearerTokenEnvKey = "AWS_BEARER_TOKEN_SIGNING_NAME"; @@ -22,14 +22,14 @@ describe("fromEnvBearerToken", () => { describe("throws error", () => { it("when signingName is not passed", async () => { - await expect(fromEnvBearerToken()()).rejects.toThrow( + await expect(fromEnvSigningName()()).rejects.toThrow( "Please pass 'signingName' to compute environment variable key" ); expect(getBearerTokenEnvKey).not.toHaveBeenCalled(); }); it("when token is not present in environment variable", async () => { - await expect(fromEnvBearerToken(mockInit)()).rejects.toThrow( + await expect(fromEnvSigningName(mockInit)()).rejects.toThrow( `Token not present in '${mockBearerTokenEnvKey}' environment variable` ); expect(getBearerTokenEnvKey).toHaveBeenCalledWith(mockInit.signingName); @@ -39,7 +39,7 @@ describe("fromEnvBearerToken", () => { it("returns token from environment variable", async () => { const mockBearerToken = "mock-bearer-token"; process.env[mockBearerTokenEnvKey] = mockBearerToken; - const token = await fromEnvBearerToken(mockInit)(); + const token = await fromEnvSigningName(mockInit)(); expect(token).toEqual({ token: mockBearerToken }); expect(getBearerTokenEnvKey).toHaveBeenCalledWith(mockInit.signingName); }); diff --git a/packages/token-providers/src/fromEnvBearerToken.ts b/packages/token-providers/src/fromEnvSigningName.ts similarity index 83% rename from packages/token-providers/src/fromEnvBearerToken.ts rename to packages/token-providers/src/fromEnvSigningName.ts index 500289d5e560..c0a358bbaeed 100644 --- a/packages/token-providers/src/fromEnvBearerToken.ts +++ b/packages/token-providers/src/fromEnvSigningName.ts @@ -5,7 +5,7 @@ import { TokenProviderError } from "@smithy/property-provider"; /** * @public */ -export interface FromEnvBearerTokenInit extends CredentialProviderOptions { +export interface FromEnvSigningNameInit extends CredentialProviderOptions { signingName?: string; } @@ -19,10 +19,10 @@ export interface FromEnvBearerTokenInit extends CredentialProviderOptions { * * @public */ -export const fromEnvBearerToken = - ({ logger, signingName }: FromEnvBearerTokenInit = {}): TokenIdentityProvider => +export const fromEnvSigningName = + ({ logger, signingName }: FromEnvSigningNameInit = {}): TokenIdentityProvider => async () => { - logger?.debug?.("@aws-sdk/token-providers - fromEnvBearerToken"); + logger?.debug?.("@aws-sdk/token-providers - fromEnvSigningName"); if (!signingName) { throw new TokenProviderError("Please pass 'signingName' to compute environment variable key", { logger }); diff --git a/packages/token-providers/src/index.ts b/packages/token-providers/src/index.ts index 7dc8d6a2997e..ae204f848bac 100644 --- a/packages/token-providers/src/index.ts +++ b/packages/token-providers/src/index.ts @@ -1,4 +1,4 @@ -export * from "./fromEnvBearerToken"; +export * from "./fromEnvSigningName"; export * from "./fromSso"; export * from "./fromStatic"; export * from "./nodeProvider"; From b41bdf4199854ff100155cbcf8945ecac67ece22 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Thu, 22 May 2025 15:04:18 +0000 Subject: [PATCH 5/5] docs: add documentation about fromEnvSigningName --- packages/token-providers/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/token-providers/README.md b/packages/token-providers/README.md index 9078019d1f6b..ce609821a54b 100644 --- a/packages/token-providers/README.md +++ b/packages/token-providers/README.md @@ -27,6 +27,15 @@ import { fromSso } from "@aws-sdk/token-providers"; const ssoToken = await fromSso(); ``` +## Env Token Provider with Signing Name + +```ts +import { fromEnvSigningName } from "@aws-sdk/token-providers"; + +// returns token from environment, where token's key is based on signing name. +const envSigningNameToken = await fromEnvSigningName({ signingName: "signing name" }); +``` + ## Token Provider Chain ```ts