---
title: 使用 ProjectConnector 連接終端使用者帳號
description: 在 TypeScript 後端使用 ProjectConnector，為 SaaS 使用者連接帳號並代使用者執行操作。
lang: zh-TW
canonical_url: https://oomol.com/zh-tw/docs/project-connector/
markdown_url: https://oomol.com/zh-tw/docs/project-connector.md
---

# 使用 ProjectConnector 連接終端使用者帳號

當產品裡的每個使用者都要連接自己的 provider 帳號時，使用 `ProjectConnector`。你的後端透過 `externalUserId` 識別使用者，建立授權連結，儲存 connected account ID，再代該使用者執行 action。

這條路徑使用形如 `oo_proj_…` 的 project API key，與 `Connector` 使用的個人 `api_…` key 相互獨立。

## 準備 project

撰寫運行期流程前，先在 OOMOL Console 建立：

1. 一個 Connector project。
2. 使用者可以連接的每個 service 對應的 provider config。
3. 一個儲存在後端密鑰管理系統中的 project API key。

[Connector for SaaS 使用指南](/zh-tw/docs/connector-saas/)包含 Console 設定步驟與對應的 REST 請求。

## 安裝並初始化

```sh
npm install @oomol-lab/connector
```

```ts
import { ProjectConnector } from "@oomol-lab/connector";

const project = new ProjectConnector({
  apiKey: process.env.OOMOL_PROJECT_API_KEY!,
});
```

## 建立 OAuth 授權請求

使用業務資料庫中的穩定使用者 ID 作為 `externalUserId`：

```ts
const request = await project.connect.oauth("user_42", {
  service: "gmail",
  connectionName: "work",
  returnUri: "https://app.example.com/connected",
});

redirectUserTo(request.authorizationUrl);
```

使用者完成授權後，等待請求進入最終狀態：

```ts
const connected = await project.waitForConnection(request);

if (connected.status === "connected") {
  saveConnectedAccountId(connected.connectedAccountId);
}
```

`project.connect.oauth` 返回的是等待使用者完成的授權請求。授權成功後，`waitForConnection` 才會在請求結果中返回 `connectedAccountId`。

對於 API key 和自訂憑據類型的 provider，使用 `connect.apiKey` 或 `connect.customCredential`。這兩個方法會同步驗證憑據並返回 connected account。

## 代一個使用者執行 action

```ts
const result = await project.execute(
  "user_42",
  "gmail.search_threads",
  { query: "is:unread" },
  { connectedAccountId: "ca-1" },
);
```

已經儲存 `connectedAccountId` 時，優先顯式傳入。它會選擇一個確定的帳號，避免依賴「最新 active 帳號」。如果產品使用穩定 alias，也可以傳 `connectionName`。

同一個請求或任務需要執行多次操作時，可以透過 `forUser` 綁定一次使用者：

Slack 範例要求該使用者已有名為「work」的連線。請使用後端為該 Slack 帳號儲存的連線名稱。forUser 只綁定使用者；帳號選擇器應傳入 execute 的選項。

```ts
const user = project.forUser("user_42");
await user.execute(
  "slack.post_message",
  { channel: "#general", text: "shipped" },
  { connectionName: "work" },
);
```

## 明確產品邊界

你的產品負責鑑權自己的使用者，並控制使用者可以使用哪些 providers 與 actions。Project API key 只儲存在後端；始終傳入一致的 `externalUserId`，並把返回的帳號選擇器儲存到對應業務使用者下。

[TypeScript SDK 參考](/zh-tw/docs/connector-sdk/)包含授權請求與 connected account 的生命週期欄位、精確 action 類型、錯誤、重試、等待選項和完整 `ProjectConnector` API。
