feat(bedrock): support Bearer token auth for Converse API (#3125)

Adds bearer token authentication for the Bedrock Converse API, enabling
users to authenticate with an API key instead of SigV4/IAM credentials.

When a bearer token is available (via `options.bearerToken` or the
`AWS_BEARER_TOKEN_BEDROCK` env var), the provider:
1. Sets dummy credentials to prevent SDK credential resolution errors
2. Injects middleware after SigV4 signing that replaces the Authorization
   header with `Bearer <token>` and removes SigV4-specific headers

This uses the official `bedrock:CallWithBearerToken` IAM action, which
is a documented AWS feature for API key auth on Bedrock endpoints.

Use case: users who receive a Bedrock API key (bearer token) from the
AWS console or their admin, without having IAM access keys or instance
roles. Similar to how ANTHROPIC_API_KEY works for direct Anthropic API.

Required IAM permission on the token's identity:
  bedrock:CallWithBearerToken

Tested: Bearer token successfully authenticates against Bedrock Converse
API (returns correct 403 for missing IAM permission, not auth format error).
SigV4 path is unchanged when no bearer token is set.
This commit is contained in:
wirjo
2026-04-17 07:34:18 +10:00
committed by GitHub
parent 5476b56e41
commit 22085a9a17

View File

@@ -74,6 +74,12 @@ export interface BedrockOptions extends StreamOptions {
* Tags appear in AWS Cost Explorer split cost allocation data.
* @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html */
requestMetadata?: Record<string, string>;
/** Bearer token for Bedrock API key authentication.
* When set, bypasses SigV4 signing and sends Authorization: Bearer <token> instead.
* Requires `bedrock:CallWithBearerToken` IAM permission on the token's identity.
* Set via AWS_BEARER_TOKEN_BEDROCK env var or pass directly.
* @see https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonbedrock.html */
bearerToken?: string;
}
type Block = (TextContent | ThinkingContent | ToolCall) & { index?: number; partialJson?: string };
@@ -110,6 +116,9 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream", BedrockOpt
profile: options.profile,
};
// Resolve bearer token for API key auth (bypasses SigV4)
const bearerToken = options.bearerToken || process.env.AWS_BEARER_TOKEN_BEDROCK || undefined;
// in Node.js/Bun environment only
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
// Region resolution: explicit option > env vars > SDK default chain.
@@ -130,6 +139,15 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream", BedrockOpt
};
}
// Bearer token auth: use API key instead of SigV4 signing.
// Requires bedrock:CallWithBearerToken IAM permission.
if (bearerToken && process.env.AWS_BEDROCK_SKIP_AUTH !== "1") {
config.credentials = {
accessKeyId: "bearer-token-auth",
secretAccessKey: "bearer-token-auth",
};
}
if (
process.env.HTTP_PROXY ||
process.env.HTTPS_PROXY ||
@@ -164,6 +182,22 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream", BedrockOpt
try {
const client = new BedrockRuntimeClient(config);
// Inject bearer token middleware after SigV4 signing
if (bearerToken) {
client.middlewareStack.addRelativeTo(
(next) => async (args: any) => {
if (args.request?.headers) {
args.request.headers["authorization"] = `Bearer ${bearerToken}`;
delete args.request.headers["x-amz-date"];
delete args.request.headers["x-amz-security-token"];
delete args.request.headers["x-amz-content-sha256"];
}
return next(args);
},
{ relation: "after", toMiddleware: "awsAuthMiddleware", name: "bearerTokenAuth" },
);
}
const cacheRetention = resolveCacheRetention(options.cacheRetention);
let commandInput = {
modelId: model.id,