---
type: study
created: 2026-08-11
updated: 2026-08-11
sensitivity: standard
status: verified
tags:
  - study
  - langchain
  - langsmith
  - smith-api
  - oauth2
  - oidc
topic: LangSmith Smith API OAuth2、OIDC、PKCE 与 Device Flow
sources:
  - https://docs.langchain.com/langsmith/smith-api/oauth/approve-oauth2-authorization-request
  - https://docs.langchain.com/langsmith/smith-api/oauth/authorize-a-device-code
  - https://docs.langchain.com/langsmith/smith-api/oauth/create-an-oauth-client
  - https://docs.langchain.com/langsmith/smith-api/oauth/delete-an-oauth-client
  - https://docs.langchain.com/langsmith/smith-api/oauth/exchange-grant-for-oauth2-tokens
  - https://docs.langchain.com/langsmith/smith-api/oauth/get-an-oauth-client
  - https://docs.langchain.com/langsmith/smith-api/oauth/get-oauth2-authorization-server-metadata
  - https://docs.langchain.com/langsmith/smith-api/oauth/get-openid-connect-provider-configuration
  - https://docs.langchain.com/langsmith/smith-api/oauth/get-openid-connect-userinfo
  - https://docs.langchain.com/langsmith/smith-api/oauth/get-public-oauth2-client-metadata
  - https://docs.langchain.com/langsmith/smith-api/oauth/initiate-oauth2-authorization
  - https://docs.langchain.com/langsmith/smith-api/oauth/list-authorized-applications
  - https://docs.langchain.com/langsmith/smith-api/oauth/list-oauth-clients
  - https://docs.langchain.com/langsmith/smith-api/oauth/register-an-oauth2-dynamic-client
  - https://docs.langchain.com/langsmith/smith-api/oauth/request-oauth2-device-authorization
  - https://docs.langchain.com/langsmith/smith-api/oauth/revoke-an-authorized-application
  - https://docs.langchain.com/langsmith/smith-api/oauth/revoke-an-oauth2-token
  - https://docs.langchain.com/langsmith/smith-api/oauth/rotate-an-oauth-client-secret
  - https://docs.langchain.com/langsmith/smith-api/oauth/update-an-oauth-client
last_verified: 2026-08-11
---

# Smith API：OAuth2、OIDC、PKCE 与 Device Flow

LangSmith 同时提供 OAuth 2.0 authorization code + PKCE、RFC 8628 device flow、refresh token、RFC 7591 dynamic registration、RFC 7009 revocation 和 OIDC discovery/userinfo。Client 管理是 organization-scoped；授权 consent 还必须核对用户可访问的 organization/workspace。

## Discovery

| 端点 | 公开性 | 返回 |
|---|---|---|
| `GET /.well-known/oauth-authorization-server` | OpenAPI 标有可选认证方案 | issuer、authorize/token/device/register/revoke/JWKS、grant/response/scope、PKCE methods、resource support |
| `GET /.well-known/openid-configuration` | public | OIDC endpoints、claims、signing algorithms、subject types |
| `GET /oauth/client/{clientID}` | public | name/logo/homepage/terms/privacy 等非敏感 consent 展示字段 |
| `GET /userinfo` | Bearer | sub、email/verified、name/picture、LangSmith org ID/name |

OIDC client 必须验证 issuer、audience、signature、expiry、nonce/state，不因为 discovery 来自官方就跳过 token validation。Public client metadata 不能返回 secret、内部 redirect 或组织私密配置。

## Authorization Code + PKCE

```mermaid
sequenceDiagram
    participant C as Client
    participant B as Browser/User
    participant L as LangSmith OAuth
    C->>L: GET /oauth/authorize + client_id + redirect_uri + challenge S256 + state
    L-->>B: 302 consent page
    B->>L: POST /oauth/authorize/approve + org/workspace + challenge
    L-->>B: redirect_uri + authorization code + state
    C->>L: POST /oauth/token + code + verifier + redirect_uri
    L-->>C: access + refresh + id token + workspace_id
```

`/oauth/authorize` 要求 `response_type=code`、registered redirect、`code_challenge_method=S256`。Approve 是 authenticated multipart request；organization 必须等于当前身份，workspace 可选但必须属于 organization 且用户可访问。`state` 防 CSRF，client 必须生成、保存并恒定时间比较。

Token endpoint 按 `grant_type` 分派：`authorization_code` 需要 code/verifier/redirect；device flow 需要 device_code；refresh 需要 refresh_token。成功响应含 `access_token`、`expires_in`、可选 ID/refresh token、token type 与 workspace ID。Authorization code、PKCE verifier、refresh token 都视为 secret，单次/短期使用。

## Device Authorization Flow

1. Client `POST /oauth/device/code`，只传 client ID，获得 device code、user code、verification URI、expiry、poll interval。
2. 用户在已登录页面输入 user code；页面 `POST /oauth/device/authorize`，同时指定匹配当前身份的 organization 与可选 workspace。
3. Device 按服务器 `interval` 轮询 `/oauth/token` 的 device grant，直到 authorized、expired 或 denied。

不得缩短服务器 interval 强轮询；device/user code 要足够随机、短期、一次性、限速并防撞库。CLI/无头设备应把 verification URI 和 user code 清晰展示，但不能把 device code 写到共享日志。

## Client 管理

Organization owner 可在 `/api/v1/platform/oauth/clients` 创建、列表、读取、Patch、删除，或 `/{id}/rotate-secret`：

- client type 为 public/confidential；confidential create/rotate 只显示一次 secret；
- 配置 name、redirect URIs、allowed scopes、grant types、logo/homepage/policy/TOS；
- Patch 可 disable client；rotate 立即使旧 secret 失效；delete 成功 204。

生产轮换要在支持双 secret 的前提下无损切换；该接口的语义是立即 invalidating previous secret，若没有重叠窗口，必须协调停机/瞬时部署。Metadata URI 仅允许可信 HTTPS，前端展示外部 logo/link 时要防追踪与内容注入。

## Dynamic Client Registration

`POST /oauth/register` 实现 RFC 7591，公开注册只签发 **public client**；redirect 仅允许受控 loopback、HTTPS 或 native URI，body 上限 8 KiB，成功 201。Request 可含 redirect URIs、name、grant/response、scope、token auth method 等。

Dynamic registration 是攻击面：限制速率/总量、严查 scheme/host/port、拒绝 credential-in-URL 与通配 redirect，不允许借 logo/policy URI SSRF。官方变更记录还说明 headless HTTP redirect 只接受 `127.0.0.1` 或 `[::1]`，不接受 `localhost`；客户端应优先读实时 metadata/错误，而不是硬编码旧规则。

## Authorized apps 与撤销

- `GET /api/v1/platform/oauth/authorized-apps` 列当前用户授权的 app、scopes 与授权时间；
- `DELETE .../{clientID}` 撤销该 app 并使用户在此 app 下的 active tokens 失效；
- `POST /oauth/revoke` 接受 access/refresh token，按 RFC 7009 无论 token 是否存在都返回 200，防止 token 探测。

撤销后的 resource server 仍需实时/短缓存验证，不能接受到 JWT 过期才生效的长窗口。Client 对 revoke 200 只能认定“请求已被接受为幂等处理”，不能据此证明 token 之前存在。

## 安全与错误处理

- Public client 永远不把 client secret 当保护手段，必须 PKCE；confidential client 把 secret 放服务器 secret store。
- Redirect URI 做 exact match；`state`、nonce、PKCE、issuer/audience 全部验证。
- Scope 默认最小；组织/workspace 选择只能从 authenticated identity 的授权集合中取。
- Token 不进 URL、浏览器持久存储、trace 或 error detail；refresh token rotation/reuse detection 由产品实时能力决定，上线前验证。
- 400 是 OAuth request/token error；401 未认证；403 当前用户/组织无权；404 隐藏或不存在；500 不应自动重放 authorization code。
- Client secret create/rotate 响应丢失时不能通过 GET 取回，只能再次受控 rotate。

