如何创建 OAuth 客户端
API 版本 2026-10-affable-towhee
在集成页面按下“创建客户端”之前,先决定三件事:客户端可以做什么、由哪个进程持有它的密钥,以及由谁为它的调用付费。身份验证指南说明了规则;本页将这些规则应用到两家虚构的公司 Luba 和 Farducks 上。
Luba:Dive Deck
Luba 经营自动驾驶潜艇,提供运输和拼乘服务。它的 Dive Deck 在舱内屏幕上为每位乘客显示本次下潜的一句短语,使用的是乘客正在学习的语言;Luba 的运营团队则关注额度还剩多少。
Luba 创建一个客户端 Luba Dive Deck,允许它“生成词汇”(vocab:generate)和“读取用量”(usage:read),计费方式为“套餐内额度”(allowance)。两个进程共用这个客户端,每个进程在换取时只申请自己需要的权限范围。省略 scope 的换取会获得该客户端被允许的全部权限范围;申请客户端未被允许的权限范围会使整个换取被拒绝,返回 invalid_scope,权限范围绝不会被悄悄缩小。
调度服务器负责编写每次下潜的短语。它只申请 vocab:generate,因此即使从它那里泄露的令牌也无法读取 Luba 的用量。
export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
-u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
--data-urlencode "scope=vocab:generate" | jq -r '.access_token // error(.error)')"curl -N -X POST "https://api.getlingara.com/v1/vocab/stream" \
-H "Authorization: Bearer $LINGARA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"level":2,"source_lang":"en","target_lang":"zh","count":8}'运营仪表板是第二个服务器端进程,使用相同的客户端 ID 和密钥。它只申请 usage:read,用来读取额度还剩多少。
export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
-u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
--data-urlencode "scope=usage:read" | jq -r '.access_token // error(.error)')"curl "https://api.getlingara.com/v1/usage" \
-H "Authorization: Bearer $LINGARA_TOKEN"两个进程都运行在 Luba 的服务器上。舱内的平板电脑向调度服务器请求短语,从不持有密钥或令牌,因为乘客能接触到的设备上的任何东西都能被读取。身份验证指南中的“将密钥和令牌保存在服务器上”一节解释了原因。
同一个客户端,作为可克隆并运行的项目: integrations/luba-dive-deck
Farducks:Batter Rewards
Farducks 是一家炸鱼薯条便利店连锁。在订单下锅炸制时,Batter Rewards 会员应用会向 Farducks 自己的后端请求一份简短的课程计划,然后再把它读回来。应用和收银机调用的是 Farducks 的后端,从不调用 Lingara,因此两者都不持有密钥。
Farducks 创建一个客户端 Farducks Batter Rewards,允许它“创建课程计划”(lesson_plans:write)和“读取课程计划”(lesson_plans:read),计费方式为“套餐内额度”(allowance)。这是目前创建客户端时唯一可用的计费方式,而且客户端的计费方式在创建时就已固定。另一种方式 metered(“按量付费”)在身份验证指南的“由谁为调用付费”一节中介绍。
后端只申请 lesson_plans:write 并创建课程计划。响应以流式返回,其中的 started 事件带有该计划的 plan_id。
export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
-u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
--data-urlencode "scope=lesson_plans:write" | jq -r '.access_token // error(.error)')"curl -N -X POST "https://api.getlingara.com/v1/lesson-plans" \
-H "Authorization: Bearer $LINGARA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"context":"Ordering food at a night market","source_lang":"en","target_lang":"zh","level":2}'将 ID 设为该 plan_id,然后申请 lesson_plans:read,把计划读回来。一次换取可以申请客户端的多个权限范围,在 scope 中以空格分隔;这里的每条命令只申请一个,因为每条命令都只由一次调用组成。
export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
-u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
--data-urlencode "scope=lesson_plans:read" | jq -r '.access_token // error(.error)')"curl "https://api.getlingara.com/v1/lesson-plans/$ID" \
-H "Authorization: Bearer $LINGARA_TOKEN"有一天,密钥被粘贴进了一张支持工单。Farducks 在集成页面上按下“新建密钥”并将其部署到后端,等旧密钥的“上次使用”日期不再变化后,再对旧密钥按下“撤销”。从那一刻起,用旧密钥换取的每个访问令牌都会被拒绝。身份验证指南中的“轮换密钥”一节介绍了最多两个密钥的限制,以及为什么客户端唯一的密钥无法撤销。
同一个客户端,作为可克隆并运行的项目: integrations/farducks-batter-rewards
下一步
身份验证指南介绍了换取的错误、令牌过期时该怎么做,以及轮换规则。版本指南介绍了客户端固定的版本,以及如何为单次调用选择另一个版本。
如译文与英文参考文档不一致,以英文参考文档为准。