跳至主要內容

Webhook 請求 (Webhooks request)

當 webhook 事件觸發時,Logto 會向所有訂閱該事件的端點發送 POST 請求。完整事件目錄請參閱 Webhook 事件;本頁說明 Logto 傳送的請求格式

請求標頭

Key可自訂說明
user-agent預設為 Logto (https://logto.io/)
content-type預設為 application/json
logto-signature-sha-256請求主體的簽章。詳見 保護你的 webhook

可自訂標頭可透過 安全 webhook 設定覆寫。

請求主體概覽

主體為 JSON 物件。其具體格式取決於事件所屬類別:

類別事件觸發時機
使用者流程PostRegisterPostSignInPostResetPassword使用者完成由 Experience API 處理的註冊、登入或重設密碼流程時。
資料變更User.*Role.*Scope.*Organization.*OrganizationRole.*OrganizationScope.*透過 Management API 呼叫或 Experience API 使用者流程導致底層資料模型變更時。
例外Identifier.LockoutMessage.RateLimitedGrant.LimitExceeded安全事件,例如連續驗證失敗導致帳號鎖定等。

每個類別都包含一組共用欄位。各類別會再加上自身的請求上下文欄位及事件專屬 payload。

共用欄位

無論類別,所有 webhook 傳送都會包含:

欄位型別選填說明
hookIdstringLogto 中的 webhook 設定識別碼。
eventstring觸發本次傳送的事件。
createdAtstringPayload 建立時間,ISO 8601 格式。
userAgentstring觸發請求的 user-agent。

每個類別也會包含觸發請求的 IP 位址:使用者流程事件欄位名為 userIp,資料變更與例外事件欄位名為 ip。語意相同,僅為相容歷史命名。

使用者流程事件 payload

事件: PostRegisterPostSignInPostResetPassword

當使用者完成由 Experience API 處理的註冊、登入或重設密碼流程時觸發。除了共用欄位外,主體還包含:

欄位型別選填說明
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'使用者流程事件型別。分別對應 PostSignIn / PostRegister / PostResetPassword。欄位名保留歷史命名。
sessionIdstring本事件的 Session ID(非 Interaction ID),如適用。
userIpstring觸發請求的 IP 位址。
userIdstring本事件關聯的使用者 ID,如適用。
userUserEntity本事件關聯的使用者實體,如適用。
applicationIdstring本事件關聯的應用程式 ID,如適用。
applicationApplicationEntity本事件關聯的應用程式實體,如適用。

Entity 格式

type UserEntity = {
id: string;
username?: string;
primaryEmail?: string;
primaryPhone?: string;
name?: string;
avatar?: string;
customData?: object;
identities?: object;
lastSignInAt?: string;
createdAt?: string;
applicationId?: string;
isSuspended?: boolean;
};
enum ApplicationType {
Native = 'Native',
SPA = 'SPA',
Traditional = 'Traditional',
MachineToMachine = 'MachineToMachine',
Protected = 'Protected',
SAML = 'SAML',
}

type ApplicationEntity = {
id: string;
type: ApplicationType;
name: string;
description?: string;
};

完整欄位請參閱 使用者應用程式

資料變更事件 payload

事件: 所有 User.*Role.*Scope.*Organization.*OrganizationRole.*OrganizationScope.* 事件。完整目錄請見 Webhook 事件 → 資料變更 webhook 事件

主體內容包含:

Experience API 上下文欄位

當變更由 Experience API 的使用者流程觸發時(如註冊時的 User.Created 或個人資料更新時的 User.Data.Updated),會包含:

欄位型別選填說明
interactionEvent'SignIn' | 'Register' | 'ForgotPassword'產生變更的使用者流程事件型別。欄位名保留歷史命名。
sessionIdstring本事件的 Session ID(非 Interaction ID),如適用。
applicationIdstring應用程式 ID,如適用。
applicationApplicationEntity應用程式實體,如適用。

Management API 上下文欄位

當變更由 Management API 呼叫觸發時會包含:

欄位型別選填說明
pathstring觸發本 webhook 的 API 呼叫路徑。
methodstringAPI 呼叫的 HTTP 方法。
statusnumberAPI 呼叫的回應狀態碼。
paramsobjectAPI 呼叫的 koa path params。
matchedRoutestringkoa 匹配到的路由。Logto 用於 webhook 事件篩選。

事件專屬資料 payload

每個資料變更事件都包含頂層 data 欄位,攜帶受影響的實體,若無法以單一實體摘要(如刪除與成員變更事件)則為 null。部分事件還有額外頂層欄位,Organization.Membership.Updated 為一例,詳見下文。

使用者事件

事件欄位型別選填說明
User.CreateddataUserEntity新建立的使用者實體。
User.Data.UpdateddataUserEntity更新後的使用者實體。
User.Deleteddatanull/

角色事件

type Role = {
id: string;
name: string;
description: string;
type: 'User' | 'MachineToMachine';
isDefault: boolean;
};
type Scope = {
id: string;
name: string;
description: string;
resourceId: string;
createdAt: number;
};
事件欄位型別選填說明
Role.CreateddataRole新建立的角色實體。
Role.Data.UpdateddataRole更新後的角色實體。
Role.Deleteddatanull/
Role.Scopes.UpdateddataScope[]指派給該角色的更新後權限範圍 (scopes)。
Role.Scopes.UpdatedroleIdstring權限範圍所屬角色 ID。(僅在建立角色時預先指派權限範圍時提供)

權限 (Scope) 事件

事件欄位型別選填說明
Scope.CreateddataScope新建立的權限範圍實體。
Scope.Data.UpdateddataScope更新後的權限範圍實體。
Scope.Deleteddatanull/

組織事件

type Organization = {
id: string;
name: string;
description?: string;
customData: object;
createdAt: number;
};
事件欄位型別選填說明
Organization.CreateddataOrganization新建立的組織實體。
Organization.Data.UpdateddataOrganization更新後的組織實體。
Organization.Deleteddatanull/
Organization.Membership.Updateddatanull/變更內容由頂層 delta 陣列描述,詳見 Organization.Membership.Updated payload
Organization.Membership.Updated payload

除了共用欄位與適用的 API 上下文欄位(Management API 路由用 Management API 上下文,即時佈建用 Experience API 上下文),Organization.Membership.Updated 事件會在 payload 頂層(與 eventcreatedAt 等同層,不在 data 內,該欄位永遠為 null)攜帶 organizationId 及可選的 delta 陣列。

欄位型別選填說明
organizationIdstring變更成員的組織 ID。
addedUserIdsstring[]本次觸發新增的使用者 ID。若無新增或不影響使用者成員則省略。
removedUserIdsstring[]本次觸發移除的使用者 ID。若無移除則省略。
addedApplicationIdsstring[]本次觸發新增的應用程式 ID。若無新增或不影響應用程式成員則省略。
removedApplicationIdsstring[]本次觸發移除的應用程式 ID。若無移除則省略。

這四個 delta 陣列可選且具加值性:對於不預期這些欄位的消費端,既有 payload 格式不變,且舊有 data: null 欄位仍會保留。

觸發來源與可能出現的 delta 欄位
觸發來源可能出現的 delta 欄位
POST /organizations/:id/usersaddedUserIds
PUT /organizations/:id/usersaddedUserIdsremovedUserIds
DELETE /organizations/:id/users/:userIdremovedUserIds
POST /organizations/:id/applicationsaddedApplicationIds
PUT /organizations/:id/applicationsaddedApplicationIdsremovedApplicationIds
DELETE /organizations/:id/applications/:applicationIdremovedApplicationIds
PUT /organization-invitations/:id/status(Accepted)addedUserIds
即時佈建新增使用者至新組織addedUserIds
空 delta 欄位會省略(缺席 ≠ 空變更)

空的 delta 陣列會完全省略於 payload。例如,PUT /organizations/:id/users 若將成員集替換為現有成員集,則無實質變更,payload 僅剩 { organizationId },四個 delta 欄位皆缺席。重複新增現有成員或已是成員的邀請再接受亦同。

消費端必須將缺席欄位視為「該側無變更」,而非「空變更」。

單一陣列上限(靜默截斷)

每個 delta 陣列上限為 5000 筆。若單次 Management API 呼叫新增或移除超過 5000 位使用者(或應用程式),對應 delta 陣列會靜默截斷為前 5000 筆。payload 內不會標示已達上限。

若你的應用程式會進行大規模管理操作,單次可能影響超過 5000 位成員,請將陣列長度正好為 5000 視為需透過 Management API 重新比對成員:

  • GET /organizations/:id/users:完整使用者成員。
  • GET /organizations/:id/applications:完整應用程式成員。

此設計與 GitHub 的 push 事件類似,該事件將 commits 上限設為 20,並引導消費端使用 compare API 取得完整清單。

跳過無操作事件

如要在消費端跳過無操作(無 delta 欄位)事件,可依 delta 陣列是否存在過濾:

if (
payload.addedUserIds?.length ||
payload.removedUserIds?.length ||
payload.addedApplicationIds?.length ||
payload.removedApplicationIds?.length
) {
// 有實際成員變更,處理之
}

?.lengthundefined[] 皆為 falsy,因此此判斷式無論欄位缺席或(假設未來)為空陣列皆適用。

範例 payload

新增使用者(POST /organizations/:id/users):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_001"]
}

取代使用者成員集(PUT /organizations/:id/users):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedUserIds": ["u_002"],
"removedUserIds": ["u_001"]
}

移除使用者(DELETE /organizations/:id/users/:userId):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_001"]
}

新增應用程式(POST /organizations/:id/applications):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"addedApplicationIds": ["app_xyz"]
}

重複新增現有成員、無操作 PUT 或已是成員的邀請再接受(無實質變更):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc"
}

批次操作觸發 5000 筆上限(靜默截斷):

{
"event": "Organization.Membership.Updated",
"organizationId": "org_abc",
"removedUserIds": ["u_0001", "u_0002", "/* … 共 5000 筆 */"]
}

若發現陣列長度正好為 5000,應主動比對 GET /organizations/:id/users(或 /applications)。

組織角色事件

type OrganizationRole = {
id: string;
name: string;
description?: string;
};
type OrganizationScope = {
id: string;
name: string;
description?: string;
};
事件欄位型別選填說明
OrganizationRole.CreateddataOrganizationRole新建立的組織角色實體。
OrganizationRole.Data.UpdateddataOrganizationRole更新後的組織角色實體。
OrganizationRole.Deleteddatanull/
OrganizationRole.Scopes.Updateddatanull/
OrganizationRole.Scopes.UpdatedorganizationRoleIdstring權限範圍所屬角色 ID。(僅在建立角色時預先指派權限範圍時提供)

組織權限(scope)事件

事件欄位型別選填說明
OrganizationScope.CreateddataOrganizationScope新建立的組織權限範圍實體。
OrganizationScope.Data.UpdateddataOrganizationScope更新後的組織權限範圍實體。
OrganizationScope.Deleteddatanull/

例外事件 payload

事件: Identifier.LockoutMessage.RateLimitedGrant.LimitExceeded

於安全事件時觸發,例如連續驗證失敗導致帳號鎖定,或因應用程式同時登入裝置數超限而撤銷授權。

每個例外事件都包含共用欄位ip 欄位(格式同資料變更事件)。其餘欄位依事件而異。

Identifier.Lockout

來源為使用者流程,因此主體也包含 Experience API 上下文欄位,並加上:

enum SignInIdentifier {
Email = 'email',
Phone = 'phone',
Username = 'username',
}
欄位型別選填說明
typeSignInIdentifier使用者識別型別,如 email、phone 或 username。
valuestring觸發鎖定的使用者識別值。

Message.RateLimited

來源為使用者流程,因此主體也包含 Experience API 上下文欄位,並加上:

欄位型別選填說明
actionstring被限流的動作,例如 VerificationCodeSend
recipientstring觸發發送速率限制的 email 或手機號碼。

Grant.LimitExceeded

當成功授權導致使用者超過應用程式的 最大同時驗證裝置數maxAllowedGrants)時觸發,Logto 會撤銷該應用程式最舊的授權。

此事件由 OIDC 授權端點發出,包含 interactionEventsessionId。除共用欄位與 ip 外,主體還包含:

欄位型別選填說明
userIdstring被撤銷授權的使用者。
applicationIdstring超過 maxAllowedGrants 限制的應用程式。
applicationApplicationEntity應用程式實體。若無法於傳送時解析則省略。
maxAllowedGrantsnumber事件觸發時應用程式設定的上限。
preRevocationActiveGrantCountnumber撤銷前該使用者於此應用程式持有的有效授權數(含本次新發放者)。
revokedGrantIdsstring[]實際被撤銷的授權 ID,依舊到新排序。

範例 payload:

{
"hookId": "hook_abc",
"event": "Grant.LimitExceeded",
"createdAt": "2024-01-01T00:00:00.000Z",
"ip": "192.168.0.1",
"userAgent": "Mozilla/5.0",
"userId": "u_001",
"applicationId": "app_xyz",
"application": {
"id": "app_xyz",
"type": "SPA",
"name": "My app",
"description": "My app description"
},
"maxAllowedGrants": 2,
"preRevocationActiveGrantCount": 3,
"revokedGrantIds": ["grant_001"]
}

傳送說明:

  • 被撤銷的授權紀錄會於撤銷時一併刪除,因此 revokedGrantIds 內的 ID 之後無法再透過授權查詢端點或 Console 查到(僅回傳有效授權)。如需留存,請自行保存這些 ID。
  • 僅當實際有授權被撤銷時才會觸發事件。若授權未超過上限則不會產生事件。
  • 每次授權超過上限都會觸發一次事件,因此使用者若不斷從超過允許數量的裝置登入,每次都會有一筆撤銷事件。
  • 傳送採 fire-and-forget:慢速或失敗的端點不會阻擋或影響使用者授權。失敗的傳送會如其他 webhook 一樣記錄於稽核日誌。