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

# OAuth 客户端凭据

> 配置限定范围的服务账号客户端，处理一次性密钥，并在请求结果不确定时安全恢复。

当您的后端集成需要短期访问令牌，或您的安全策略要求使用此类令牌时，请使用 OAuth 客户端凭据。每个客户端仅属于一个服务账号和一个组织。\*\*OAuth 为可选项：\*\*对于能够安全存储并轮换密钥的私有服务器集成，使用限定范围的 API 密钥即可。有关如何在两种方法之间进行选择以及服务账号如何适用，请参阅[身份验证](/zh-Hans/developers/v1/authentication)。

<Note>
  必须为您的组织启用 OAuth 访问。您的设置会提供区域令牌端点、颁发者、受众以及客户端身份验证方法。如果您需要这些设置，或无法访问客户端管理功能，请联系 Living Security 支持团队。
</Note>

客户端凭据授权代表的是您的服务账号。它不会让任何个人登录，也不会要求客户授权某个应用程序。通过浏览器进行的委托授权属于另一项 OAuth 功能，这些操作并不提供该功能。

## 开始之前

* 创建一个[服务账号](/zh-Hans/developers/developer-hub/service-accounts)，仅授予集成所需的权限。
* 使用具有 `service_account:manage` 以及您要授予新客户端的每项权限的管理凭据。目标账号也必须拥有这些权限。客户端无法扩大任何一个账号的权限范围。
* 选择组织所在的[区域](/zh-Hans/developers/v1/regions)。API 凭据和 OAuth 访问令牌必须用于相应的区域 API 主机。
* 请将客户端密钥和令牌保存在服务器端的密钥存储中。切勿将其放入浏览器代码、移动应用程序、源代码管理或请求日志中。

## 创建客户端

`POST /v1/oauth_clients` 需要 `service_account_id`、由明确的 `scopes` 组成的非空列表，以及 `Idempotency-Key`。不接受通配符。每个客户端最多支持 100 个范围，总长度不超过 4,096 个字符。每个服务账号最多可拥有 20 个客户端或未完成的创建/清理操作。撤销会立即拒绝 API 访问。在确认远程清理完成之前，客户端或结果不确定的提供方创建操作会继续计入该限制。已放弃的预留，或已证实在提供方开始处理之前就已失败的创建操作，可以安全地释放其占用的名额。其重试密钥仍属于原始尝试；在决定是否创建替代客户端之前，请先恢复该回执。

请为本次创建尝试选择一个重试密钥，并在发送请求**之前**将其持久化保存。重试密钥应为 1–255 个可见 ASCII 字符，不含空格。在响应丢失后，请使用相同的账号、范围、管理主体、区域和 API 版本重复使用该密钥。在同一服务账号下轮换管理凭据不会产生新的重试标识。

安装 Python 的 `requests` 软件包。通过您常规的密钥和配置管理方式加载以下环境值：

| 变量 | 值 |
| - | - |
| `LIVING_SECURITY_API_KEY` | 管理 API 密钥 |
| `LIVING_SECURITY_REGION` | `us` 或 `eu` |
| `LIVING_SECURITY_SERVICE_ACCOUNT_ID` | 目标服务账号 ID |
| `LIVING_SECURITY_OAUTH_CREATE_KEY` | 先前已持久化保存的重试密钥 |

```python Python theme={null}
import os
import requests

HOSTS = {
    "us": "https://api.us-east-1.livingsecurity.ai/v1",
    "eu": "https://api.eu-west-1.livingsecurity.ai/v1",
}
base = HOSTS[os.environ["LIVING_SECURITY_REGION"]]
response = requests.post(
    f"{base}/oauth_clients",
    auth=("apikey", os.environ["LIVING_SECURITY_API_KEY"]),
    headers={
        "Living-Security-Version": "2026-07-01",
        "Idempotency-Key": os.environ["LIVING_SECURITY_OAUTH_CREATE_KEY"],
    },
    json={
        "service_account_id": os.environ["LIVING_SECURITY_SERVICE_ACCOUNT_ID"],
        "scopes": ["organization:read"],
    },
    timeout=(5, 30),
    allow_redirects=False,
)
try:
    if response.status_code != 201:
        raise RuntimeError(
            f"Client creation needs review: HTTP {response.status_code}; "
            f"request_id={response.headers.get('Request-Id', 'unknown')}"
        )
    client = response.json()
    if client.get("object") != "oauth_client" or not client.get("id"):
        raise RuntimeError("Unexpected client receipt; preserve the retry key")
    if client.get("status") != "active" or not client.get("client_secret"):
        raise RuntimeError(
            f"Client {client['id']} needs recovery; no usable secret was returned"
        )
    # Persist client['id'], client['client_id'], and client['client_secret']
    # directly in your secret manager before using the client. Do not print them.
finally:
    response.close()
```

该示例只发送一次请求，并将结果保留在内存中。在生产环境中运行之前，请在标记位置添加您的密钥管理器的写入操作。当结果不确定时，示例会刻意要求您做出决定，而不是悄然再创建一个客户端。出现网络异常时，同样需要执行下文的恢复步骤。

创建和回执响应使用 `201`，并包含带有 `id`、`service_account_id`、`client_id`、`scopes`、`status`、`created_at` 和 `client_secret` 的 `oauth_client` 资源。响应会标记为 `Cache-Control: no-store`。

* **`id`** 用于标识平台资源。请保存它，以便检索和撤销。
* **`client_id`** 用于在令牌交换期间标识客户端。它不是平台资源 ID。在创建待处理期间，它可能为 `null`。
* **`client_secret`** 仅返回给完成创建的那次请求。每一次重复的创建请求都会返回 `null`，包括在成功响应丢失后进行的重试。检索操作绝不会返回密钥。

## 恢复丢失或中断的响应

使用已保存的重试密钥重复相同的创建请求，即可恢复资源回执。回执反映的是当前状态，因此已撤销的客户端仍保持已撤销状态。此操作不使用通用的 24 小时缓存响应重放约定，也不会返回 `Idempotent-Replayed` 标头。

| 结果 | 后续操作 |
| - | - |
| `active`，存在密钥 | 安全保存密钥并继续接入。 |
| `active`，不存在密钥 | 无法恢复该密钥。请撤销此客户端并确认撤销完成，然后使用新的重试密钥创建替代客户端。 |
| `pending` | 创建尚未确认。请保留相同的重试密钥。检索该资源以查看状态；请勿为绕过不确定性而创建重复客户端。 |
| `revoked`、`disabled` 或 `expired` | 请勿使用此客户端。在配置替代客户端之前，请确认预期的账号配置。 |
| `409 idempotency_key_reuse` | 请求在使用现有密钥的情况下发生了更改。在决定是否需要单独创建之前，请先恢复原始操作。 |
| `409 invalid_request` | 请检查目标账号的状态和授权。如果已达到其客户端数量上限，请在重试之前完成清理；更改重试密钥不会释放容量。 |
| `429` | 请遵循 `Retry-After`；保留相同的密钥和请求。 |
| `500`、`503` 或网络超时 | 结果可能未知。请保留密钥和输入；在创建其他客户端之前，先恢复回执。 |
| `401` 或 `403` | 在重试之前，请先解决凭据、权限或授权许可方面的访问问题。 |
| `404` | 请确认 OAuth 的启用情况、区域主机以及资源归属。 |

有关请求 ID 和恢复详情，请参阅[错误](/zh-Hans/developers/v1/errors/overview)。切勿在支持请求中发送客户端密钥或访问令牌。

## 检查与撤销

使用您的管理凭据和平台资源 `id`：

| 操作 | 请求 | 成功 |
| - | - | - |
| 检查当前状态 | `GET /v1/oauth_clients/{id}` | `200`，不含密钥的客户端资源 |
| 撤销访问 | `DELETE /v1/oauth_clients/{id}` | `200`，不含密钥的已撤销客户端资源 |

撤销会阻止该客户端后续的 API 请求，包括使用已颁发令牌的请求。它不会取消 API 已接受的工作。远程凭据清理可能稍后完成。重复撤销是安全的，且无需重试密钥。如果被撤销的客户端本身就是 API 调用方，请继续使用管理凭据。

## 轮换时不中断访问

创建第二个客户端，并设置所需的范围上限。保存其密钥，使用您的区域令牌端点获取令牌，并验证集成能够使用该客户端正常工作。将集成切换到替代客户端，然后撤销旧资源。请保留一个独立的管理凭据，以便在发布出现问题时进行恢复。

访问令牌所授予的权限不能超出客户端的范围和服务账号的当前权限。移除账号权限或撤销客户端的效力优先于令牌的剩余有效期。请勿将缓存的令牌视为授权仍然有效的证明。请在令牌到期前通过再次对客户端进行身份验证来获取新的访问令牌；此授权方式不使用刷新令牌。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.