Skip to content

Commit 3dc507c

Browse files
authored
feat: support API Key authentication with API Gateway (#72)
1 parent 86e33b1 commit 3dc507c

9 files changed

Lines changed: 218 additions & 196 deletions

File tree

README.md

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -81,31 +81,13 @@ You can choose one of the following two methods for configuration
8181
<details>
8282
<summary><b>🔧 Configure SwiftChat Server (Click to expand)</b></summary>
8383

84-
> **Note**: From v2.7.0, we recommend redeploying the SwiftChat Server for better performance with API Gateway + Lambda supporting 15-minute streaming output. Your existing API Key can be reused - you only need to update the Server URL in the app.
85-
8684
### Architecture
8785

8886
![](/assets/architecture.png)
8987

90-
We use **API Gateway** combined with **AWS Lambda** to enable streaming responses for up to 15 minutes, as shown in
91-
this [example](https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examples/fastapi-response-streaming).
92-
93-
### Step 1: Set up your API Key
94-
95-
1. Sign in to your AWS console and
96-
right-click [Parameter Store](https://console.aws.amazon.com/systems-manager/parameters/) to open it in a new tab.
97-
2. Check whether you are in the [supported region](#supported-region), then click on the **Create parameter** button.
98-
3. Fill in the parameters below, leaving other options as default:
99-
100-
- **Name**: Enter a parameter name (e.g., "SwiftChatAPIKey", will be used as `ApiKeyParam` in Step 3).
88+
We use **API Gateway** combined with **AWS Lambda** to enable streaming responses for up to 15 minutes. All requests are authenticated via API Gateway's API Key validation before being forwarded to Lambda, ensuring secure access to backend services.
10189

102-
- **Type**: Select `SecureString`
103-
104-
- **Value**: Enter any string without spaces.(this will be your `API Key` in Step 4)
105-
106-
4. Click **Create parameter**.
107-
108-
### Step 2: Build and push container images to ECR
90+
### Step 1: Build and push container images to ECR
10991

11092
1. Clone this repository:
11193
```bash
@@ -128,47 +110,32 @@ this [example](https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examp
128110

129111
5. **Important**: Copy the image URI displayed at the end of the script output. You'll need this in the next step.
130112

131-
### Step 3: Deploy stack and get your API URL
113+
### Step 2: Deploy stack and get your API URL and API Key
132114

133115
1. Download the CloudFormation template:
134116
- Lambda: [SwiftChatLambda.template](https://github.com/aws-samples/swift-chat/blob/main/server/template/SwiftChatLambda.template)
135117

136-
2. Go to [CloudFormation Console](https://console.aws.amazon.com/cloudformation/home#/stacks/create/template?stackName=SwiftChatAPI) and select **Upload a template file** under **Specify template**, then upload the template file you downloaded. (Make sure you are in the same region where your API Key was created.)
118+
2. Go to [CloudFormation Console](https://console.aws.amazon.com/cloudformation/home#/stacks/create/template?stackName=SwiftChat) and select **Upload a template file** under **Specify template**, then upload the template file you downloaded.
137119

138120
3. Click **Next**, On the "Specify stack details" page, provide the following information:
139-
- **ApiKeyParam**: Enter the parameter name you used for storing the API key (e.g., "SwiftChatAPIKey")
140-
- **ContainerImageUri**: Enter the ECR image URI from Step 2 output
121+
- **ContainerImageUri**: Enter the ECR image URI from Step 1 output
141122

142123
4. Click **Next**, Keep the "Configure stack options" page as default, Read the Capabilities and Check the "I
143124
acknowledge that AWS CloudFormation might create IAM resources" checkbox at the bottom.
144125
5. Click **Next**, In the "Review and create" Review your configuration and click **Submit**.
145126

146-
Wait about 3–5 minutes for the deployment to finish, then click the CloudFormation stack and go to **Outputs** tab, you
147-
can find the **API URL** which looks like: `https://xxx.execute-api.us-east-1.amazonaws.com/v1`
127+
6. Wait about 1-2 minutes for the deployment to finish, then click the CloudFormation stack and go to **Outputs** tab:
128+
- **APIURL**: Your API URL (e.g., `https://xxx.execute-api.us-east-1.amazonaws.com/v1`)
129+
- **ApiKeyConsole**: Click this URL to open the API Gateway API Keys console, find the key named `SwiftChat-api-key` and copy the API Key value
148130

149-
### Step 4: Open the App and setup with API URL and API Key
131+
### Step 3: Open the App and setup with API URL and API Key
150132

151133
1. Launch the App, open the drawer menu, and tap **Settings**.
152-
2. Paste the `API URL` and `API Key`(The **Value** you typed in Parameter Store) Under Amazon Bedrock -> SwiftChat
153-
Server, then select your Region.
134+
2. Paste the `API URL` and `API Key` under Amazon Bedrock -> SwiftChat Server, then select your Region.
154135
3. Click the top right ✓ icon to save your configuration and start your chat.
155136

156137
Congratulations 🎉 Your SwiftChat App is ready to use!
157138

158-
### Supported Region
159-
160-
- US East (N. Virginia): us-east-1
161-
- US West (Oregon): us-west-2
162-
- Asia Pacific (Mumbai): ap-south-1
163-
- Asia Pacific (Singapore): ap-southeast-1
164-
- Asia Pacific (Sydney): ap-southeast-2
165-
- Asia Pacific (Tokyo): ap-northeast-1
166-
- Canada (Central): ca-central-1
167-
- Europe (Frankfurt): eu-central-1
168-
- Europe (London): eu-west-2
169-
- Europe (Paris): eu-west-3
170-
- South America (São Paulo): sa-east-1
171-
172139
</details>
173140

174141
## Getting Started with Other Model Providers

README_CN.md

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -77,30 +77,13 @@ SwiftChat 是一款快速响应的 AI 助手,采用 [React Native](https://rea
7777
<details>
7878
<summary><b>🔧 配置 SwiftChat 服务器(点击展开)</b></summary>
7979

80-
> **注意**:自 v2.7.0 起,我们建议重新部署 SwiftChat 服务器以获得更好的性能,支持 API Gateway + Lambda 实现最长 15 分钟的流式输出。您之前创建的 API Key 可以复用 - 只需在应用中更新服务器 URL 即可。
81-
8280
### 架构
8381

8482
![](/assets/architecture.png)
8583

86-
我们提供用 **API Gateway****AWS Lambda** 结合的方式,实现最长15分钟的流式传输,如此 [示例](https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examples/fastapi-response-streaming)
87-
所示。
88-
89-
### 步骤 1:设置您的 API 密钥
90-
91-
1. 登录您的 AWS 控制台并右键点击 [Parameter Store](https://console.aws.amazon.com/systems-manager/parameters/) 在新标签页中打开。
92-
2. 检查您是否在 [支持的区域](#支持的区域),然后点击 **创建参数** 按钮。
93-
3. 填入以下参数,其他选项保持默认:
94-
95-
- **名称**:输入参数名称(例如 "SwiftChatAPIKey",将在步骤 3 中用作 `ApiKeyParam`)。
84+
我们使用 **API Gateway****AWS Lambda** 结合的方式,实现最长 15 分钟的流式传输。所有请求通过 API Gateway 的 API Key 验证后才会转发到 Lambda,确保后端服务的安全访问。
9685

97-
- **类型**:选择 `SecureString`
98-
99-
- ****:输入任何不含空格的字符串(这将是步骤 4 中您的 `API Key`
100-
101-
4. 点击 **创建参数**
102-
103-
### 步骤 2:构建并推送容器镜像到 ECR
86+
### 步骤 1:构建并推送容器镜像到 ECR
10487

10588
1. 克隆此仓库:
10689
```bash
@@ -123,44 +106,31 @@ SwiftChat 是一款快速响应的 AI 助手,采用 [React Native](https://rea
123106

124107
5. **重要**:复制脚本输出末尾显示的镜像 URI。您将在下一步中需要它。
125108

126-
### 步骤 3:部署堆栈并获取 API URL
109+
### 步骤 2:部署堆栈并获取 API URL 和 API Key
127110

128111
1. 下载 CloudFormation 模板:
129112
- Lambda:[SwiftChatLambda.template](https://github.com/aws-samples/swift-chat/blob/main/server/template/SwiftChatLambda.template)
130113

131-
2. 前往 [CloudFormation 控制台](https://console.aws.amazon.com/cloudformation/home#/stacks/create/template?stackName=SwiftChatAPI),在**指定模板**下选择**上传模板文件**,然后上传您下载的模板文件。(确保您所在的区域与创建 API Key 的区域相同。)
114+
2. 前往 [CloudFormation 控制台](https://console.aws.amazon.com/cloudformation/home#/stacks/create/template?stackName=SwiftChat),在**指定模板**下选择**上传模板文件**,然后上传您下载的模板文件。
132115

133116
3. 点击 **下一步**,在"指定堆栈详细信息"页面,提供以下信息:
134-
- **ApiKeyParam**:输入您用于存储 API 密钥的参数名称(例如 "SwiftChatAPIKey")
135-
- **ContainerImageUri**:输入步骤 2 输出的 ECR 镜像 URI
117+
- **ContainerImageUri**:输入步骤 1 输出的 ECR 镜像 URI
136118

137119
4. 点击 **下一步**,保持"配置堆栈选项"页面为默认,阅读功能并勾选底部的"我确认 AWS CloudFormation 可能会创建 IAM 资源"复选框。
138120
5. 点击 **下一步**,在"审核并创建"中检查您的配置并点击 **提交**
139121

140-
等待约 3-5 分钟完成部署,然后点击 CloudFormation 堆栈并转到 **输出** 选项卡,您可以找到 **API URL**,类似于:`https://xxx.execute-api.us-east-1.amazonaws.com/v1`
122+
6. 等待约 1-2 分钟完成部署,然后点击 CloudFormation 堆栈并转到 **输出** 选项卡:
123+
- **APIURL**:您的 API URL(例如:`https://xxx.execute-api.us-east-1.amazonaws.com/v1`
124+
- **ApiKeyConsole**:点击此 URL 打开 API Gateway API Keys 控制台,找到名为 `<StackName>-api-key` 的密钥并复制 API Key 值
141125

142-
### 步骤 4:打开应用并使用 API URL 和 API Key 进行设置
126+
### 步骤 3:打开应用并使用 API URL 和 API Key 进行设置
143127

144128
1. 启动应用,打开抽屉菜单,点击 **设置**
145-
2. 粘贴 `API URL``API Key`(您在 Parameter Store 中输入的 ****到 Amazon Bedrock -> SwiftChat Server 下,然后选择您的区域。
129+
2. 粘贴 `API URL``API Key` 到 Amazon Bedrock -> SwiftChat Server 下,然后选择您的区域。
146130
3. 点击右上角 ✓ 图标保存配置并开始聊天。
147131

148132
恭喜 🎉 您的 SwiftChat 应用已准备就绪!
149133

150-
### 支持的区域
151-
152-
- 美国东部(弗吉尼亚北部):us-east-1
153-
- 美国西部(俄勒冈):us-west-2
154-
- 亚太地区(孟买):ap-south-1
155-
- 亚太地区(新加坡):ap-southeast-1
156-
- 亚太地区(悉尼):ap-southeast-2
157-
- 亚太地区(东京):ap-northeast-1
158-
- 加拿大(中部):ca-central-1
159-
- 欧洲(法兰克福):eu-central-1
160-
- 欧洲(伦敦):eu-west-2
161-
- 欧洲(巴黎):eu-west-3
162-
- 南美洲(圣保罗):sa-east-1
163-
164134
</details>
165135

166136
## 其他模型提供商入门指南

assets/architecture.png

-6.9 KB
Loading

react-native/src/api/bedrock-api.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,7 @@ export const invokeBedrockWithCallBack = async (
131131

132132
const options = {
133133
method: 'POST',
134-
headers: {
135-
accept: '*/*',
136-
'content-type': 'application/json',
137-
Authorization: 'Bearer ' + getApiKey(),
138-
},
134+
headers: getAuthHeaders('application/json'),
139135
body: JSON.stringify(bodyObject),
140136
signal: controller.signal,
141137
reactNative: { textStreaming: true },
@@ -332,11 +328,7 @@ export const requestAllModels = async (): Promise<AllModel> => {
332328
};
333329
const options = {
334330
method: 'POST',
335-
headers: {
336-
accept: 'application/json',
337-
'content-type': 'application/json',
338-
Authorization: 'Bearer ' + getApiKey(),
339-
},
331+
headers: getAuthHeaders(),
340332
body: JSON.stringify(bodyObject),
341333
reactNative: { textStreaming: true },
342334
};
@@ -379,11 +371,7 @@ export const requestToken = async (): Promise<TokenResponse | null> => {
379371

380372
const options = {
381373
method: 'POST',
382-
headers: {
383-
accept: 'application/json',
384-
'content-type': 'application/json',
385-
Authorization: 'Bearer ' + getApiKey(),
386-
},
374+
headers: getAuthHeaders(),
387375
body: JSON.stringify(bodyObject),
388376
reactNative: { textStreaming: true },
389377
};
@@ -411,11 +399,7 @@ export const requestUpgradeInfo = async (
411399
const url = getApiPrefix() + '/upgrade';
412400
const options = {
413401
method: 'POST',
414-
headers: {
415-
accept: 'application/json',
416-
'content-type': 'application/json',
417-
Authorization: 'Bearer ' + getApiKey(),
418-
},
402+
headers: getAuthHeaders(),
419403
body: JSON.stringify({
420404
os: os,
421405
version: version,
@@ -457,11 +441,7 @@ export const genImage = async (
457441
};
458442
const options = {
459443
method: 'POST',
460-
headers: {
461-
accept: '*/*',
462-
'content-type': 'application/json',
463-
Authorization: 'Bearer ' + getApiKey(),
464-
},
444+
headers: getAuthHeaders('application/json'),
465445
body: JSON.stringify(bodyObject),
466446
signal: controller.signal,
467447
reactNative: { textStreaming: true },
@@ -570,6 +550,24 @@ function getApiPrefix(): string {
570550
}
571551
}
572552

553+
function getAuthHeaders(
554+
contentType: string = 'application/json'
555+
): Record<string, string> {
556+
const apiUrl = getApiUrl();
557+
const isApiGateway =
558+
apiUrl.includes('.execute-api.') && apiUrl.includes('.amazonaws.com');
559+
const headers: Record<string, string> = {
560+
accept: contentType === 'application/json' ? 'application/json' : '*/*',
561+
'content-type': contentType,
562+
};
563+
if (isApiGateway) {
564+
headers['x-api-key'] = getApiKey();
565+
} else {
566+
headers.Authorization = 'Bearer ' + getApiKey();
567+
}
568+
return headers;
569+
}
570+
573571
export const isEnableThinking = (): boolean => {
574572
return isThinkingModel() && getThinkingEnabled();
575573
};

0 commit comments

Comments
 (0)