优化和重构代码,增加前端可以设置加密配置数据的密钥

This commit is contained in:
glay 2024-11-22 22:03:42 +08:00
parent bd68df1d9b
commit b0c1ccd0a0
12 changed files with 138 additions and 154 deletions

View File

@ -70,8 +70,9 @@ WHITE_WEBDAV_ENDPOINTS=
### bedrock (optional) ### bedrock (optional)
AWS_REGION= AWS_REGION=
AWS_ACCESS_KEY= AWS_ACCESS_KEY=AKIA
AWS_SECRET_KEY= AWS_SECRET_KEY=
### Assign this with a secure, randomly generated key
### Assign this with a secure, randomly generated key ### Generate a secure, random key that is at least 32 characters long. You can use a password generator or a command like this:
### openssl rand -base64 32
ENCRYPTION_KEY= ENCRYPTION_KEY=

View File

@ -52,29 +52,6 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
msg: "you are not allowed to access with your own api key", msg: "you are not allowed to access with your own api key",
}; };
} }
// Special handling for Bedrock
if (modelProvider === ModelProvider.Bedrock) {
const region = serverConfig.awsRegion;
const accessKeyId = serverConfig.awsAccessKey;
const secretAccessKey = serverConfig.awsSecretKey;
console.log("[Auth] Bedrock credentials:", {
region,
accessKeyId: accessKeyId ? "***" : undefined,
secretKey: secretAccessKey ? "***" : undefined,
});
// Check if AWS credentials are provided
if (!region || !accessKeyId || !secretAccessKey) {
return {
error: true,
msg: "Missing AWS credentials. Please configure Region, Access Key ID, and Secret Access Key in settings.",
};
}
return { error: false };
}
// if user does not provide an api key, inject system api key // if user does not provide an api key, inject system api key
if (!apiKey) { if (!apiKey) {
const serverConfig = getServerSideConfig(); const serverConfig = getServerSideConfig();
@ -120,6 +97,14 @@ export function auth(req: NextRequest, modelProvider: ModelProvider) {
case ModelProvider.ChatGLM: case ModelProvider.ChatGLM:
systemApiKey = serverConfig.chatglmApiKey; systemApiKey = serverConfig.chatglmApiKey;
break; break;
case ModelProvider.Bedrock:
systemApiKey =
serverConfig.awsRegion +
":" +
serverConfig.awsAccessKey +
":" +
serverConfig.awsSecretKey;
break;
case ModelProvider.GPT: case ModelProvider.GPT:
default: default:
if (req.nextUrl.pathname.includes("azure/deployments")) { if (req.nextUrl.pathname.includes("azure/deployments")) {

View File

@ -1,5 +1,6 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import { sign, decrypt } from "../utils/aws"; import { sign } from "../utils/aws";
import { getServerSideConfig } from "../config/server";
const ALLOWED_PATH = new Set(["chat", "models"]); const ALLOWED_PATH = new Set(["chat", "models"]);
@ -18,7 +19,7 @@ function parseEventData(chunk: Uint8Array): any {
} }
return parsed.body || parsed; return parsed.body || parsed;
} catch (e) { } catch (e) {
console.error("Error parsing event data:", e); // console.error("Error parsing event data:", e);
try { try {
// Handle base64 encoded responses // Handle base64 encoded responses
const base64Match = text.match(/:"([A-Za-z0-9+/=]+)"/); const base64Match = text.match(/:"([A-Za-z0-9+/=]+)"/);
@ -76,7 +77,7 @@ async function* transformBedrockStream(
const parsed = parseEventData(value); const parsed = parseEventData(value);
if (!parsed) continue; if (!parsed) continue;
console.log("Parsed response:", JSON.stringify(parsed, null, 2)); // console.log("Parsed response:", JSON.stringify(parsed, null, 2));
// Handle Titan models // Handle Titan models
if (modelId.startsWith("amazon.titan")) { if (modelId.startsWith("amazon.titan")) {
@ -182,26 +183,38 @@ function validateRequest(body: any, modelId: string): void {
async function requestBedrock(req: NextRequest) { async function requestBedrock(req: NextRequest) {
const controller = new AbortController(); const controller = new AbortController();
const awsRegion = req.headers.get("X-Region") ?? "";
const awsAccessKey = req.headers.get("X-Access-Key") ?? ""; // Get AWS credentials from server config first
const awsSecretKey = req.headers.get("X-Secret-Key") ?? ""; const config = getServerSideConfig();
const awsSessionToken = req.headers.get("X-Session-Token"); let awsRegion = config.awsRegion;
const modelId = req.headers.get("X-Model-Id") ?? ""; let awsAccessKey = config.awsAccessKey;
let awsSecretKey = config.awsSecretKey;
let modelId = "";
// If server-side credentials are not available, parse from Authorization header
if (!awsRegion || !awsAccessKey || !awsSecretKey) {
const authHeader = req.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
throw new Error("Missing or invalid Authorization header");
}
const [_, credentials] = authHeader.split("Bearer ");
const [region, accessKey, secretKey, model] = credentials.split(",");
if (!region || !accessKey || !secretKey || !model) {
throw new Error("Invalid Authorization header format");
}
awsRegion = region;
awsAccessKey = accessKey;
awsSecretKey = secretKey;
modelId = model;
}
if (!awsRegion || !awsAccessKey || !awsSecretKey || !modelId) { if (!awsRegion || !awsAccessKey || !awsSecretKey || !modelId) {
throw new Error("Missing required AWS credentials or model ID"); throw new Error("Missing required AWS credentials or model ID");
} }
const decryptedAccessKey = decrypt(awsAccessKey);
const decryptedSecretKey = decrypt(awsSecretKey);
const decryptedSessionToken = awsSessionToken
? decrypt(awsSessionToken)
: undefined;
if (!decryptedAccessKey || !decryptedSecretKey) {
throw new Error("Failed to decrypt AWS credentials");
}
// Construct the base endpoint // Construct the base endpoint
const baseEndpoint = `https://bedrock-runtime.${awsRegion}.amazonaws.com`; const baseEndpoint = `https://bedrock-runtime.${awsRegion}.amazonaws.com`;
@ -236,9 +249,8 @@ async function requestBedrock(req: NextRequest) {
method: "POST", method: "POST",
url: endpoint, url: endpoint,
region: awsRegion, region: awsRegion,
accessKeyId: decryptedAccessKey, accessKeyId: awsAccessKey,
secretAccessKey: decryptedSecretKey, secretAccessKey: awsSecretKey,
sessionToken: decryptedSessionToken,
body: requestBody, body: requestBody,
service: "bedrock", service: "bedrock",
}); });

View File

@ -23,7 +23,6 @@ import { SparkApi } from "./platforms/iflytek";
import { XAIApi } from "./platforms/xai"; import { XAIApi } from "./platforms/xai";
import { ChatGLMApi } from "./platforms/glm"; import { ChatGLMApi } from "./platforms/glm";
import { BedrockApi } from "./platforms/bedrock"; import { BedrockApi } from "./platforms/bedrock";
import { encrypt } from "../utils/aws";
export const ROLES = ["system", "user", "assistant"] as const; export const ROLES = ["system", "user", "assistant"] as const;
export type MessageRole = (typeof ROLES)[number]; export type MessageRole = (typeof ROLES)[number];
@ -258,8 +257,6 @@ export function getHeaders(ignoreHeaders: boolean = false) {
const isEnabledAccessControl = accessStore.enabledAccessControl(); const isEnabledAccessControl = accessStore.enabledAccessControl();
const apiKey = isGoogle const apiKey = isGoogle
? accessStore.googleApiKey ? accessStore.googleApiKey
: isBedrock
? accessStore.awsAccessKey // Use AWS access key for Bedrock
: isAzure : isAzure
? accessStore.azureApiKey ? accessStore.azureApiKey
: isAnthropic : isAnthropic
@ -278,6 +275,18 @@ export function getHeaders(ignoreHeaders: boolean = false) {
? accessStore.iflytekApiKey && accessStore.iflytekApiSecret ? accessStore.iflytekApiKey && accessStore.iflytekApiSecret
? accessStore.iflytekApiKey + ":" + accessStore.iflytekApiSecret ? accessStore.iflytekApiKey + ":" + accessStore.iflytekApiSecret
: "" : ""
: isBedrock
? accessStore.awsRegion &&
accessStore.awsAccessKey &&
accessStore.awsSecretKey
? accessStore.awsRegion +
"," +
accessStore.awsAccessKey +
"," +
accessStore.awsSecretKey +
"," +
modelConfig.model
: ""
: accessStore.openaiApiKey; : accessStore.openaiApiKey;
return { return {
isBedrock, isBedrock,
@ -303,13 +312,10 @@ export function getHeaders(ignoreHeaders: boolean = false) {
? "x-api-key" ? "x-api-key"
: isGoogle : isGoogle
? "x-goog-api-key" ? "x-goog-api-key"
: isBedrock
? "x-api-key"
: "Authorization"; : "Authorization";
} }
const { const {
isBedrock,
isGoogle, isGoogle,
isAzure, isAzure,
isAnthropic, isAnthropic,
@ -322,28 +328,23 @@ export function getHeaders(ignoreHeaders: boolean = false) {
const authHeader = getAuthHeader(); const authHeader = getAuthHeader();
if (isBedrock) { // if (isBedrock) {
// Secure encryption of AWS credentials using the new encryption utility // // Secure encryption of AWS credentials using the new encryption utility
headers["X-Region"] = encrypt(accessStore.awsRegion); // headers["X-Region"] = encrypt(accessStore.awsRegion);
headers["X-Access-Key"] = encrypt(accessStore.awsAccessKey); // headers["X-Access-Key"] = encrypt(accessStore.awsAccessKey);
headers["X-Secret-Key"] = encrypt(accessStore.awsSecretKey); // headers["X-Secret-Key"] = encrypt(accessStore.awsSecretKey);
// } else {
const bearerToken = getBearerToken(
apiKey,
isAzure || isAnthropic || isGoogle,
);
if (accessStore.awsSessionToken) { if (bearerToken) {
headers["X-Session-Token"] = encrypt(accessStore.awsSessionToken); headers[authHeader] = bearerToken;
} } else if (isEnabledAccessControl && validString(accessStore.accessCode)) {
} else { headers["Authorization"] = getBearerToken(
const bearerToken = getBearerToken( ACCESS_CODE_PREFIX + accessStore.accessCode,
apiKey,
isAzure || isAnthropic || isGoogle,
); );
if (bearerToken) {
headers[authHeader] = bearerToken;
} else if (isEnabledAccessControl && validString(accessStore.accessCode)) {
headers["Authorization"] = getBearerToken(
ACCESS_CODE_PREFIX + accessStore.accessCode,
);
}
} }
return headers; return headers;

View File

@ -1,5 +1,6 @@
import { import {
ChatOptions, ChatOptions,
getHeaders,
LLMApi, LLMApi,
SpeechOptions, SpeechOptions,
RequestMessage, RequestMessage,
@ -233,23 +234,22 @@ export class BedrockApi implements LLMApi {
const accessStore = useAccessStore.getState(); const accessStore = useAccessStore.getState();
if (!accessStore.isValidBedrock()) { if (!accessStore.isValidBedrock()) {
throw new Error( throw new Error(
"Invalid AWS credentials. Please check your configuration.", "Invalid AWS credentials. Please check your configuration and ensure ENCRYPTION_KEY is set.",
); );
} }
try { try {
const apiEndpoint = "/api/bedrock/chat"; const apiEndpoint = "/api/bedrock/chat";
const headers = { // const headers = {
"Content-Type": requestBody.contentType || "application/json", // "Content-Type": requestBody.contentType || "application/json",
Accept: requestBody.accept || "application/json", // Accept: requestBody.accept || "application/json",
"X-Region": accessStore.awsRegion, // "X-Region": accessStore.awsRegion,
"X-Access-Key": accessStore.awsAccessKey, // "X-Access-Key": accessStore.awsAccessKey,
"X-Secret-Key": accessStore.awsSecretKey, // "X-Secret-Key": accessStore.awsSecretKey,
"X-Model-Id": modelConfig.model, // "X-Model-Id": modelConfig.model,
...(accessStore.awsSessionToken && { // "X-Encryption-Key": accessStore.bedrockEncryptionKey,
"X-Session-Token": accessStore.awsSessionToken, // };
}), const headers = getHeaders();
};
if (options.config.stream) { if (options.config.stream) {
let index = -1; let index = -1;
@ -274,7 +274,6 @@ export class BedrockApi implements LLMApi {
(text: string, runTools: ChatMessageTool[]) => { (text: string, runTools: ChatMessageTool[]) => {
try { try {
const chunkJson = JSON.parse(text); const chunkJson = JSON.parse(text);
// console.log("Received chunk:", JSON.stringify(chunkJson, null, 2));
if (chunkJson?.content_block?.type === "tool_use") { if (chunkJson?.content_block?.type === "tool_use") {
index += 1; index += 1;
currentToolArgs = ""; currentToolArgs = "";
@ -375,7 +374,6 @@ export class BedrockApi implements LLMApi {
}); });
const resJson = await res.json(); const resJson = await res.json();
// console.log("Response:", JSON.stringify(resJson, null, 2));
const message = this.extractMessage(resJson, modelConfig.model); const message = this.extractMessage(resJson, modelConfig.model);
// console.log("Extracted message:", message); // console.log("Extracted message:", message);
options.onFinish(message, res); options.onFinish(message, res);

View File

@ -79,17 +79,6 @@
pointer-events: none; pointer-events: none;
} }
.icon {
display: flex;
align-items: center;
justify-content: center;
svg {
width: 16px;
height: 16px;
}
}
&:hover { &:hover {
--delay: 0.5s; --delay: 0.5s;
width: var(--full-width); width: var(--full-width);
@ -410,8 +399,8 @@
button { button {
padding: 7px; padding: 7px;
}
} }
}
/* Specific styles for iOS devices */ /* Specific styles for iOS devices */
@media screen and (max-device-width: 812px) and (-webkit-min-device-pixel-ratio: 2) { @media screen and (max-device-width: 812px) and (-webkit-min-device-pixel-ratio: 2) {
@ -761,4 +750,4 @@
transform: translateX(0); transform: translateX(0);
} }
} }
} }

View File

@ -980,12 +980,12 @@ export function Settings() {
onChange={(e) => onChange={(e) =>
accessStore.update((access) => { accessStore.update((access) => {
const region = e.currentTarget.value; const region = e.currentTarget.value;
if (!/^[a-z]{2}-[a-z]+-\d+$/.test(region)) { if (!/^[a-z]{2}-[a-z]+-\d+$/.test(region)) {
showToast(Locale.Settings.Access.Bedrock.Region.Invalid); showToast(Locale.Settings.Access.Bedrock.Region.Invalid);
return; return;
} }
access.awsRegion = region; access.awsRegion = region;
}) })
} }
/> />
</ListItem> </ListItem>
@ -999,7 +999,7 @@ export function Settings() {
type="text" type="text"
placeholder={Locale.Settings.Access.Bedrock.AccessKey.Placeholder} placeholder={Locale.Settings.Access.Bedrock.AccessKey.Placeholder}
onChange={(e) => { onChange={(e) => {
accessStore.update((access) => { accessStore.update((access) => {
const accessKey = e.currentTarget.value; const accessKey = e.currentTarget.value;
if (accessKey && accessKey.length !== 20) { if (accessKey && accessKey.length !== 20) {
showToast(Locale.Settings.Access.Bedrock.AccessKey.Invalid); showToast(Locale.Settings.Access.Bedrock.AccessKey.Invalid);
@ -1022,11 +1022,11 @@ export function Settings() {
placeholder={Locale.Settings.Access.Bedrock.SecretKey.Placeholder} placeholder={Locale.Settings.Access.Bedrock.SecretKey.Placeholder}
onChange={(e) => { onChange={(e) => {
accessStore.update((access) => { accessStore.update((access) => {
const secretKey = e.currentTarget.value; const secretKey = e.currentTarget.value;
if (secretKey && secretKey.length !== 40) { if (secretKey && secretKey.length !== 40) {
showToast(Locale.Settings.Access.Bedrock.SecretKey.Invalid); showToast(Locale.Settings.Access.Bedrock.SecretKey.Invalid);
return; return;
} }
access.awsSecretKey = secretKey; access.awsSecretKey = secretKey;
}); });
}} }}
@ -1034,17 +1034,17 @@ export function Settings() {
/> />
</ListItem> </ListItem>
<ListItem <ListItem
title={Locale.Settings.Access.Bedrock.SessionToken.Title} title={Locale.Settings.Access.Bedrock.EncryptionKey.Title}
subTitle={Locale.Settings.Access.Bedrock.SessionToken.SubTitle} subTitle={Locale.Settings.Access.Bedrock.EncryptionKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Bedrock.SessionToken.Title} aria-label={Locale.Settings.Access.Bedrock.EncryptionKey.Title}
value={accessStore.awsSessionToken} value={accessStore.bedrockEncryptionKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Bedrock.SessionToken.Placeholder} placeholder={Locale.Settings.Access.Bedrock.EncryptionKey.Placeholder}
onChange={(e) => { onChange={(e) => {
accessStore.update( accessStore.update(
(access) => (access.awsSessionToken = e.currentTarget.value), (access) => (access.bedrockEncryptionKey = e.currentTarget.value),
); );
}} }}
maskWhenShow={true} maskWhenShow={true}

View File

@ -13,9 +13,10 @@ declare global {
OPENAI_ORG_ID?: string; // openai only OPENAI_ORG_ID?: string; // openai only
// bedrock only // bedrock only
BEDROCK_REGION?: string; AWS_REGION?: string;
BEDROCK_API_KEY?: string; AWS_ACCESS_KEY?: string;
BEDROCK_API_SECRET?: string; AWS_SECRET_KEY?: string;
ENCRYPTION_KEY?: string;
VERCEL?: string; VERCEL?: string;
BUILD_MODE?: "standalone" | "export"; BUILD_MODE?: "standalone" | "export";
@ -148,7 +149,10 @@ export const getServerSideConfig = () => {
} }
const isStability = !!process.env.STABILITY_API_KEY; const isStability = !!process.env.STABILITY_API_KEY;
const isBedrock = !!process.env.BEDROCK_API_KEY; const isBedrock =
!!process.env.AWS_REGION &&
!!process.env.AWS_ACCESS_KEY &&
!!process.env.AWS_SECRET_KEY;
const isAzure = !!process.env.AZURE_URL; const isAzure = !!process.env.AZURE_URL;
const isGoogle = !!process.env.GOOGLE_API_KEY; const isGoogle = !!process.env.GOOGLE_API_KEY;
const isAnthropic = !!process.env.ANTHROPIC_API_KEY; const isAnthropic = !!process.env.ANTHROPIC_API_KEY;
@ -182,6 +186,7 @@ export const getServerSideConfig = () => {
awsRegion: process.env.AWS_REGION, awsRegion: process.env.AWS_REGION,
awsAccessKey: process.env.AWS_ACCESS_KEY, awsAccessKey: process.env.AWS_ACCESS_KEY,
awsSecretKey: process.env.AWS_SECRET_KEY, awsSecretKey: process.env.AWS_SECRET_KEY,
bedrockEncryptionKey: process.env.ENCRYPTION_KEY,
isStability, isStability,
stabilityUrl: process.env.STABILITY_URL, stabilityUrl: process.env.STABILITY_URL,

View File

@ -361,14 +361,10 @@ const cn = {
Placeholder: "****", Placeholder: "****",
Invalid: "无效的 AWS Secret Key 格式。必须为40个字符。", Invalid: "无效的 AWS Secret Key 格式。必须为40个字符。",
}, },
SessionToken: { EncryptionKey: {
Title: "AWS Session Token (Optional)", Title: "加密密钥",
SubTitle: "Your AWS session token if using temporary credentials", SubTitle: "用于配置数据的加密密钥",
Placeholder: "Optional session token", Placeholder: "输入加密密钥",
},
Endpoint: {
Title: "AWS Bedrock Endpoint",
SubTitle: "Custom endpoint for AWS Bedrock API. Default: ",
}, },
}, },
Azure: { Azure: {

View File

@ -365,14 +365,10 @@ const en: LocaleType = {
Placeholder: "****", Placeholder: "****",
Invalid: "Invalid AWS secret key format. Must be 40 characters long.", Invalid: "Invalid AWS secret key format. Must be 40 characters long.",
}, },
SessionToken: { EncryptionKey: {
Title: "AWS Session Token (Optional)", Title: "Encryption Key",
SubTitle: "Your AWS session token if using temporary credentials", SubTitle: "Your encryption key for configuration data",
Placeholder: "Optional session token", Placeholder: "Enter encryption key",
},
Endpoint: {
Title: "AWS Bedrock Endpoint",
SubTitle: "Custom endpoint for AWS Bedrock API. Default: ",
}, },
}, },
Azure: { Azure: {

View File

@ -15,6 +15,7 @@ import {
IFLYTEK_BASE_URL, IFLYTEK_BASE_URL,
XAI_BASE_URL, XAI_BASE_URL,
CHATGLM_BASE_URL, CHATGLM_BASE_URL,
BEDROCK_BASE_URL,
} from "../constant"; } from "../constant";
import { getHeaders } from "../client/api"; import { getHeaders } from "../client/api";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
@ -51,6 +52,8 @@ const DEFAULT_XAI_URL = isApp ? XAI_BASE_URL : ApiPath.XAI;
const DEFAULT_CHATGLM_URL = isApp ? CHATGLM_BASE_URL : ApiPath.ChatGLM; const DEFAULT_CHATGLM_URL = isApp ? CHATGLM_BASE_URL : ApiPath.ChatGLM;
const DEFAULT_BEDROCK_URL = isApp ? BEDROCK_BASE_URL : ApiPath.Bedrock;
const DEFAULT_ACCESS_STATE = { const DEFAULT_ACCESS_STATE = {
accessCode: "", accessCode: "",
useCustomConfig: false, useCustomConfig: false,
@ -117,10 +120,11 @@ const DEFAULT_ACCESS_STATE = {
chatglmApiKey: "", chatglmApiKey: "",
// aws bedrock // aws bedrock
bedrokUrl: DEFAULT_BEDROCK_URL,
awsRegion: "", awsRegion: "",
awsAccessKey: "", awsAccessKey: "",
awsSecretKey: "", awsSecretKey: "",
awsSessionToken: "", bedrockEncryptionKey: "",
// server config // server config
needCode: true, needCode: true,
@ -200,7 +204,12 @@ export const useAccessStore = createPersistStore(
}, },
isValidBedrock() { isValidBedrock() {
return ensure(get(), ["awsRegion", "awsAccessKey", "awsSecretKey"]); return ensure(get(), [
"awsRegion",
"awsAccessKey",
"awsSecretKey",
"bedrockEncryptionKey",
]);
}, },
isAuthorized() { isAuthorized() {

View File

@ -3,14 +3,14 @@ import HmacSHA256 from "crypto-js/hmac-sha256";
import Hex from "crypto-js/enc-hex"; import Hex from "crypto-js/enc-hex";
import Utf8 from "crypto-js/enc-utf8"; import Utf8 from "crypto-js/enc-utf8";
import { AES, enc } from "crypto-js"; import { AES, enc } from "crypto-js";
import { getServerSideConfig } from "../config/server";
const SECRET_KEY = const serverConfig = getServerSideConfig();
process.env.ENCRYPTION_KEY || // console.info(serverConfig);
"your-secret-key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const SECRET_KEY = serverConfig.bedrockEncryptionKey || "";
if (!SECRET_KEY || SECRET_KEY.length < 32) { // console.info("======SECRET_KEY:"+SECRET_KEY);
throw new Error( if (serverConfig.isBedrock && !SECRET_KEY) {
"ENCRYPTION_KEY environment variable must be set with at least 32 characters", console.error("When use Bedrock modle,ENCRYPTION_KEY should been set!");
);
} }
export function encrypt(data: string): string { export function encrypt(data: string): string {
@ -54,7 +54,6 @@ export interface SignParams {
region: string; region: string;
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;
sessionToken?: string;
body: string; body: string;
service: string; service: string;
} }
@ -143,7 +142,6 @@ export async function sign({
region, region,
accessKeyId, accessKeyId,
secretAccessKey, secretAccessKey,
sessionToken,
body, body,
service, service,
}: SignParams): Promise<Record<string, string>> { }: SignParams): Promise<Record<string, string>> {
@ -169,11 +167,6 @@ export async function sign({
"x-amzn-bedrock-accept": "*/*", "x-amzn-bedrock-accept": "*/*",
}; };
// Add session token if present
if (sessionToken) {
headers["x-amz-security-token"] = sessionToken;
}
// Get sorted header keys (case-insensitive) // Get sorted header keys (case-insensitive)
const sortedHeaderKeys = Object.keys(headers).sort((a, b) => const sortedHeaderKeys = Object.keys(headers).sort((a, b) =>
a.toLowerCase().localeCompare(b.toLowerCase()), a.toLowerCase().localeCompare(b.toLowerCase()),
@ -230,7 +223,6 @@ export async function sign({
"X-Amz-Content-Sha256": headers["x-amz-content-sha256"], "X-Amz-Content-Sha256": headers["x-amz-content-sha256"],
"X-Amz-Date": headers["x-amz-date"], "X-Amz-Date": headers["x-amz-date"],
"X-Amzn-Bedrock-Accept": headers["x-amzn-bedrock-accept"], "X-Amzn-Bedrock-Accept": headers["x-amzn-bedrock-accept"],
...(sessionToken && { "X-Amz-Security-Token": sessionToken }),
Authorization: authorization, Authorization: authorization,
}; };
} }