> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tinyinbox.co/llms.txt
> Use this file to discover all available pages before exploring further.

# 辨識已登入訪客

> 使用簽署的身分權杖，讓 TinyInbox 信任你應用程式提供的訪客資訊。

身分驗證讓你的後端告訴 TinyInbox 已登入訪客是誰。當你希望收件匣顯示可信任的姓名、email 或使用者 ID，而不是瀏覽器自行提供的資訊時，請使用這個方式。

## 何時使用

以下情況適合使用簽署身分：

* 訪客已登入你的產品
* 你想把回覆連到自己的使用者 ID
* 你需要姓名或 email 由後端提供

如果只是公開行銷頁面，通常使用瀏覽器傳入的訪客資訊就足夠。

## 取得網站密鑰

在儀表板建立該網站的第一組 identity signing secret。TinyInbox 只會顯示新的密鑰一次，因此離開頁面前請先複製到你的後端環境變數。

你也可以從 API 建立或輪替：

```http theme={null}
POST /sites/{siteId}/security/rotate-identity-secret
Authorization: Bearer <user-session-token>
```

回應會包含新的 `identitySecret`，且只顯示這一次。既有密鑰不會再次回傳。

## 簽署 token

身分 token 必須：

* 使用 `HS256` 演算法
* 如果你的 JWT library 會設定 type header，請使用 `typ: "JWT"`。沒有
  `typ` 的 token 可以接受，但其他 `typ` 值會被拒絕。
* 將 `aud` 設為 `tinyinbox-widget-identity`
* 包含 `userId` 或 `sub`
* 可選擇包含 `name`、`email` 和 `siteKey`
* 設定短時間過期

後端路由範例：

```ts theme={null}
import { SignJWT } from "jose"

export async function GET() {
  const token = await new SignJWT({
    userId: user.id,
    name: user.name,
    email: user.email,
    siteKey: "tin_your_site_key",
  })
    .setProtectedHeader({ alg: "HS256", typ: "JWT" })
    .setAudience("tinyinbox-widget-identity")
    .setExpirationTime("30m")
    .sign(new TextEncoder().encode(process.env.TINYINBOX_IDENTITY_SECRET))

  return Response.json({ identityToken: token })
}
```

## 傳給小工具

提供一個瀏覽器可呼叫、會回傳 `{ identityToken }` 的 endpoint，然後從 client-only code 把這個 token 傳給 widget。請繼續使用 TinyInbox 儀表板複製出來的 widget script；不要在應用程式碼裡重新組合 widget URL 或 site key。

如果你對已登入訪客使用 signed identity，不要再為同一位訪客呼叫 `TinyInbox.identify({ name, email })`。可信任的 `name` 和 `email` 應該放在 signed token 裡；兩種方式同時使用可能先建立匿名 session，接著又切換到 signed visitor session。

對於已登入 app 頁面，請在 auth state 已知後取得 token，然後傳給 TinyInbox。如果這段程式碼可以在複製的 widget script 載入前執行，指令會先排入 queue，第一個 widget session 就會是 signed visitor。

```js theme={null}
const { identityToken } = await fetch("/api/tinyinbox/identity").then((res) =>
  res.json()
)

window.TinyInbox = window.TinyInbox || []
window.TinyInbox.push(["identify", { identityToken }])
```

如果你偏好明確等待 ready hook，或頁面在 auth state 確定前就已經安裝 widget script，則等 runtime ready 後傳入 token：

```js theme={null}
const { identityToken } = await fetch("/api/tinyinbox/identity").then((res) =>
  res.json()
)

function onTinyInboxReady(callback) {
  if (window.TinyInbox && window.TinyInbox.isReady) {
    callback(window.TinyInbox)
    return
  }

  window.addEventListener(
    "tinyinbox:ready",
    (event) => callback(event.detail),
    { once: true }
  )
}

onTinyInboxReady((TinyInbox) => {
  TinyInbox.identify({ identityToken })
})
```

你也可以在 script 標籤中使用 `data-tinyinbox-identity` 屬性直接提供 token。

## 輪替密鑰

如果網站的 identity secret 外洩，或你需要新的密鑰，請輪替密鑰。輪替後，請更新你的後端環境變數。

API 路由：

```http theme={null}
POST /sites/{siteId}/security/rotate-identity-secret
Authorization: Bearer <user-session-token>
```

用舊密鑰簽署的身分 token 會在輪替後停止運作。
