zoom-oauth
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseZoom OAuth
Zoom OAuth
Background reference for Zoom auth and token lifecycle behavior. Prefer first, then use this skill for the exact flow, scope, and error details.
setup-zoom-oauthZoom身份认证和令牌生命周期行为的背景参考,请优先使用,再通过本技能获取具体的流程、作用域和错误详情。
setup-zoom-oauthZoom OAuth
Zoom OAuth
Authentication and authorization for Zoom APIs.
Zoom API的身份验证与授权说明。
📖 Complete Documentation
📖 完整文档
For comprehensive guides, production patterns, and troubleshooting, see Integrated Index section below.
Quick navigation:
- 5-Minute Runbook - Preflight checks before deep debugging
- OAuth Flows - Which flow to use and how each works
- Token Lifecycle - Expiration, refresh, and revocation
- Production Examples - Redis caching, MySQL storage, auto-refresh
- Troubleshooting - Error codes 4700-4741
如需全面指南、生产模式和故障排查方案,请参阅下方的集成索引部分。
快速导航:
- 5分钟运行手册 - 深度调试前的预检检查
- OAuth 流程 - 不同场景适用的流程及工作原理
- 令牌生命周期 - 过期、刷新和吊销规则
- 生产示例 - Redis缓存、MySQL存储、自动刷新实现
- 故障排查 - 4700-4741错误码说明
Prerequisites
前置条件
- Zoom app created in Marketplace
- Client ID and Client Secret
- For S2S OAuth: Account ID
- 已在Zoom市场创建应用
- 拥有Client ID和Client Secret
- 若使用S2S OAuth:需提供Account ID
Four Authorization Use Cases
四种授权使用场景
| Use Case | App Type | Grant Type | Industry Name |
|---|---|---|---|
| Account Authorization | Server-to-Server | | Client Credentials Grant, M2M, Two-legged OAuth |
| User Authorization | General | | Authorization Code Grant, Three-legged OAuth |
| Device Authorization | General | | Device Authorization Grant (RFC 8628) |
| Client Authorization | General | | Client Credentials Grant (chatbot-scoped) |
| 场景 | 应用类型 | Grant Type | 行业通用名称 |
|---|---|---|---|
| 账户授权 | 服务端到服务端 | | 客户端凭证授权、M2M、双阶段OAuth |
| 用户授权 | 通用 | | 授权码授权、三阶段OAuth |
| 设备授权 | 通用 | | 设备授权(RFC 8628) |
| 客户端授权 | 通用 | | 客户端凭证授权(仅限聊天机器人作用域) |
Industry Terminology
行业术语
| Term | Meaning |
|---|---|
| Two-legged OAuth | No user involved (client ↔ server) |
| Three-legged OAuth | User involved (user ↔ client ↔ server) |
| M2M | Machine-to-Machine (backend services) |
| Public client | Can't keep secrets (mobile, SPA) → use PKCE |
| Confidential client | Can keep secrets (backend servers) |
| PKCE | Proof Key for Code Exchange (RFC 7636), pronounced "pixy" |
| 术语 | 含义 |
|---|---|
| 双阶段OAuth | 无用户参与(客户端 ↔ 服务端) |
| 三阶段OAuth | 有用户参与(用户 ↔ 客户端 ↔ 服务端) |
| M2M | 机器到机器(后端服务场景) |
| 公开客户端 | 无法安全存储密钥(移动端、SPA)→ 需使用PKCE |
| 机密客户端 | 可以安全存储密钥(后端服务) |
| PKCE | 授权码交换证明密钥(RFC 7636),发音为"pixy" |
Which Flow Should I Use?
我应该使用哪种流程?
┌─────────────────────┐
│ What are you │
│ building? │
└──────────┬──────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Backend │ │ App for other │ │ Chatbot only │
│ automation │ │ users/accounts │ │ (Team Chat) │
│ (your account) │ │ │ │ │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
▼ │ ▼
┌─────────────────┐ │ ┌─────────────────┐
│ ACCOUNT │ │ │ CLIENT │
│ (S2S OAuth) │ │ │ (Chatbot) │
└─────────────────┘ │ └─────────────────┘
│
▼
┌─────────────────────┐
│ Does device have │
│ a browser? │
└──────────┬──────────┘
│
┌───────────────┴───────────────┐
│ NO YES│
▼ ▼
┌─────────────────────────┐ ┌─────────────────┐
│ DEVICE │ │ USER │
│ (Device Flow) │ │ (Auth Code) │
│ │ │ │
│ Examples: │ │ + PKCE if │
│ • Smart TV │ │ public client │
│ • Meeting SDK device │ │ │
└─────────────────────────┘ └─────────────────┘ ┌─────────────────────┐
│ 你要开发什么类型的 │
│ 应用? │
└──────────┬──────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 后端自动化 │ │ 面向其他用户/ │ │ 仅聊天机器人 │
│ (自有账户) │ │ 账户的应用 │ │ (团队聊天) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
▼ │ ▼
┌─────────────────┐ │ ┌─────────────────┐
│ 账户授权 │ │ │ 客户端授权 │
│ (S2S OAuth) │ │ │ (聊天机器人) │
└─────────────────┘ │ └─────────────────┘
│
▼
┌─────────────────────┐
│ 设备是否有浏览器? │
└──────────┬──────────┘
│
┌───────────────┴───────────────┐
│ 否 是│
▼ ▼
┌─────────────────────────┐ ┌─────────────────┐
│ 设备授权 │ │ 用户授权 │
│ (设备流程) │ │ (授权码流程) │
│ │ │ + PKCE(若为公开 │
│ 示例: │ │ 客户端) │
│ • 智能电视 │ │ │
│ • Meeting SDK设备 │ │ │
└─────────────────────────┘ └─────────────────┘Account Authorization (Server-to-Server OAuth)
账户授权(Server-to-Server OAuth)
For backend automation without user interaction.
适用于无需用户交互的后端自动化场景。
Request Access Token
请求访问令牌
bash
POST https://zoom.us/oauth/token?grant_type=account_credentials&account_id={ACCOUNT_ID}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}bash
POST https://zoom.us/oauth/token?grant_type=account_credentials&account_id={ACCOUNT_ID}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Response
返回结果
json
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "user:read:user:admin",
"api_url": "https://api.zoom.us"
}json
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "user:read:user:admin",
"api_url": "https://api.zoom.us"
}Refresh
刷新规则
Access tokens expire after 1 hour. No separate refresh flow - just request a new token.
访问令牌1小时后过期,无单独的刷新流程,直接请求新令牌即可。
User Authorization (Authorization Code Flow)
用户授权(授权码流程)
For apps that act on behalf of users.
适用于代表用户执行操作的应用。
Step 1: Redirect User to Authorize
步骤1:重定向用户到授权页面
https://zoom.us/oauth/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}Use for consent, but for token exchange.
https://zoom.us/oauth/authorizehttps://zoom.us/oauth/tokenOptional Parameters:
| Parameter | Description |
|---|---|
| CSRF protection, maintains state through flow |
| For PKCE (see below) |
| |
https://zoom.us/oauth/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}授权同意页面使用,令牌交换使用。
https://zoom.us/oauth/authorizehttps://zoom.us/oauth/token可选参数:
| 参数 | 说明 |
|---|---|
| CSRF防护,维持整个流程的状态 |
| 用于PKCE(见下文) |
| |
Step 2: User Authorizes
步骤2:用户授权
- User signs in and grants permission
- Redirects to with authorization code:
redirect_urihttps://example.com/?code={AUTHORIZATION_CODE}
- 用户登录并授予权限
- 授权完成后重定向到并携带授权码:
redirect_urihttps://example.com/?code={AUTHORIZATION_CODE}
Step 3: Exchange Code for Token
步骤3:用授权码交换令牌
bash
POST https://zoom.us/oauth/token?grant_type=authorization_code&code={CODE}&redirect_uri={REDIRECT_URI}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}With PKCE: Add parameter.
code_verifierbash
POST https://zoom.us/oauth/token?grant_type=authorization_code&code={CODE}&redirect_uri={REDIRECT_URI}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}使用PKCE时: 添加参数。
code_verifierResponse
返回结果
json
{
"access_token": "eyJ...",
"token_type": "bearer",
"refresh_token": "eyJ...",
"expires_in": 3600,
"scope": "user:read:user",
"api_url": "https://api.zoom.us"
}json
{
"access_token": "eyJ...",
"token_type": "bearer",
"refresh_token": "eyJ...",
"expires_in": 3600,
"scope": "user:read:user",
"api_url": "https://api.zoom.us"
}Refresh Token
刷新令牌
bash
POST https://zoom.us/oauth/token?grant_type=refresh_token&refresh_token={REFRESH_TOKEN}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}- Access tokens expire after 1 hour
- Refresh token lifetime can vary; ~90 days is common for some user-based flows. Treat it as configuration/behavior that can change and rely on runtime errors + re-auth fallback.
- Always use the latest refresh token for the next request
- If refresh token expires, redirect user to authorization URL to restart flow
bash
POST https://zoom.us/oauth/token?grant_type=refresh_token&refresh_token={REFRESH_TOKEN}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}- 访问令牌1小时后过期
- 刷新令牌有效期不固定,部分用户场景通常为90天,建议将其视为可配置的可变行为,依赖运行时错误+重新授权作为兜底方案
- 后续请求始终使用最新的刷新令牌
- 若刷新令牌过期,重定向用户到授权URL重启流程
User-Level vs Account-Level Apps
用户级与账户级应用对比
| Type | Who Can Authorize | Scope Access |
|---|---|---|
| User-level | Any individual user | Scoped to themselves |
| Account-level | User with admin permissions | Account-wide access (admin scopes) |
| 类型 | 可授权角色 | 作用域访问权限 |
|---|---|---|
| 用户级 | 任意个人用户 | 仅授权用户自身的数据范围 |
| 账户级 | 拥有管理员权限的用户 | 全账户范围访问(管理员作用域) |
Device Authorization (Device Flow)
设备授权(设备流程)
For devices without browsers (e.g., Meeting SDK apps).
适用于无浏览器的设备(例如Meeting SDK应用)。
Prerequisites
前置条件
Enable "Use App on Device" in: Features > Embed > Enable Meeting SDK
在以下路径开启「在设备上使用应用」:功能 > 嵌入 > 启用Meeting SDK
Step 1: Request Device Code
步骤1:请求设备码
bash
POST https://zoom.us/oauth/devicecode?client_id={CLIENT_ID}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}bash
POST https://zoom.us/oauth/devicecode?client_id={CLIENT_ID}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Response
返回结果
json
{
"device_code": "DEVICE_CODE",
"user_code": "abcd1234",
"verification_uri": "https://zoom.us/oauth_device",
"verification_uri_complete": "https://zoom.us/oauth/device/complete/{CODE}",
"expires_in": 900,
"interval": 5
}json
{
"device_code": "DEVICE_CODE",
"user_code": "abcd1234",
"verification_uri": "https://zoom.us/oauth_device",
"verification_uri_complete": "https://zoom.us/oauth/device/complete/{CODE}",
"expires_in": 900,
"interval": 5
}Step 2: User Authorization
步骤2:用户授权
Direct user to:
- and display
verification_urifor manual entry, ORuser_code - (user code prefilled)
verification_uri_complete
User signs in and allows the app.
引导用户操作:
- 访问并手动输入展示的
verification_uri,或者user_code - 直接访问(已自动填充user_code)
verification_uri_complete
用户登录并允许应用访问权限。
Step 3: Poll for Token
步骤3:轮询获取令牌
Poll at the (5 seconds) until user authorizes:
intervalbash
POST https://zoom.us/oauth/token?grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={DEVICE_CODE}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}按照返回的(默认5秒)轮询接口,直到用户完成授权:
intervalbash
POST https://zoom.us/oauth/token?grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code={DEVICE_CODE}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Response
返回结果
json
{
"access_token": "eyJ...",
"token_type": "bearer",
"refresh_token": "eyJ...",
"expires_in": 3599,
"scope": "user:read:user user:read:token",
"api_url": "https://api.zoom.us"
}json
{
"access_token": "eyJ...",
"token_type": "bearer",
"refresh_token": "eyJ...",
"expires_in": 3599,
"scope": "user:read:user user:read:token",
"api_url": "https://api.zoom.us"
}Polling Responses
轮询响应说明
| Response | Meaning | Action |
|---|---|---|
| Token returned | User authorized | Store tokens, done |
| User hasn't authorized yet | Keep polling at interval |
| Polling too fast | Increase interval by 5 seconds |
| Device code expired (15 min) | Restart flow from Step 1 |
| User denied authorization | Handle denial, don't retry |
| 响应 | 含义 | 操作 |
|---|---|---|
| 返回令牌 | 用户已授权 | 存储令牌,流程结束 |
| 用户尚未完成授权 | 按间隔继续轮询 |
| 轮询频率过高 | 轮询间隔增加5秒 |
| 设备码已过期(15分钟有效期) | 从步骤1重启流程 |
| 用户拒绝授权 | 处理拒绝逻辑,无需重试 |
Polling Implementation
轮询实现示例
javascript
async function pollForToken(deviceCode, interval) {
while (true) {
await sleep(interval * 1000);
try {
const response = await axios.post(
`https://zoom.us/oauth/token?grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=${deviceCode}`,
null,
{ headers: { 'Authorization': `Basic ${credentials}` } }
);
return response.data; // Success - got tokens
} catch (error) {
const err = error.response?.data?.error;
if (err === 'authorization_pending') continue;
if (err === 'slow_down') { interval += 5; continue; }
throw error; // expired_token or access_denied
}
}
}javascript
async function pollForToken(deviceCode, interval) {
while (true) {
await sleep(interval * 1000);
try {
const response = await axios.post(
`https://zoom.us/oauth/token?grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=${deviceCode}`,
null,
{ headers: { 'Authorization': `Basic ${credentials}` } }
);
return response.data; // 成功获取令牌
} catch (error) {
const err = error.response?.data?.error;
if (err === 'authorization_pending') continue;
if (err === 'slow_down') { interval += 5; continue; }
throw error; // 令牌过期或用户拒绝授权
}
}
}Refresh
刷新规则
Same as User Authorization. If refresh token expires, restart device flow from Step 1.
与用户授权流程一致,若刷新令牌过期,从步骤1重启设备授权流程。
Client Authorization (Chatbot)
客户端授权(聊天机器人)
For chatbot message operations only.
仅适用于聊天机器人消息操作场景。
Request Token
请求令牌
bash
POST https://zoom.us/oauth/token?grant_type=client_credentials
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}bash
POST https://zoom.us/oauth/token?grant_type=client_credentials
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Response
返回结果
json
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "imchat:bot",
"api_url": "https://api.zoom.us"
}json
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "imchat:bot",
"api_url": "https://api.zoom.us"
}Refresh
刷新规则
Tokens expire after 1 hour. No refresh flow - just request a new token.
令牌1小时后过期,无刷新流程,直接请求新令牌即可。
Using Access Tokens
使用访问令牌
Call API
调用API
bash
GET https://api.zoom.us/v2/users/me
Headers:
Authorization: Bearer {ACCESS_TOKEN}bash
GET https://api.zoom.us/v2/users/me
Headers:
Authorization: Bearer {ACCESS_TOKEN}Me Context
Me上下文
Replace with to target the token's associated user:
userIDme| Endpoint | Methods |
|---|---|
| GET, PATCH |
| GET |
| GET, POST |
将替换为即可指向令牌关联的用户:
userIDme| 接口 | 支持方法 |
|---|---|
| GET, PATCH |
| GET |
| GET, POST |
Revoke Access Token
吊销访问令牌
Works for all authorization types.
bash
POST https://zoom.us/oauth/revoke?token={ACCESS_TOKEN}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}适用于所有授权类型。
bash
POST https://zoom.us/oauth/revoke?token={ACCESS_TOKEN}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Response
返回结果
json
{
"status": "success"
}json
{
"status": "success"
}PKCE (Proof Key for Code Exchange)
PKCE(授权码交换证明密钥)
For public clients that can't securely store secrets (mobile apps, SPAs, desktop apps).
适用于无法安全存储密钥的公开客户端(移动应用、SPA、桌面应用)。
When to Use PKCE
何时使用PKCE
| Client Type | Use PKCE? | Why |
|---|---|---|
| Mobile app | Yes | Can't securely store client secret |
| Single Page App (SPA) | Yes | JavaScript is visible to users |
| Desktop app | Yes | Binary can be decompiled |
| Meeting SDK (client-side) | Yes | Runs on user's device |
| Backend server | Optional | Can keep secrets, but PKCE adds security |
| 客户端类型 | 是否需要PKCE? | 原因 |
|---|---|---|
| 移动应用 | 是 | 无法安全存储客户端密钥 |
| 单页应用(SPA) | 是 | JavaScript代码对用户可见 |
| 桌面应用 | 是 | 二进制文件可被反编译 |
| Meeting SDK(客户端侧) | 是 | 运行在用户设备上 |
| 后端服务 | 可选 | 可安全存储密钥,但PKCE可额外提升安全性 |
How PKCE Works
PKCE工作原理
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Client │ │ Zoom │ │ Zoom │
│ App │ │ Auth │ │ Token │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ 1. Generate code_verifier (random) │ │
│ 2. Create code_challenge = SHA256(verifier) │
│ │ │
│ ─────── /authorize + code_challenge ──► │ │
│ │ │
│ ◄────── authorization_code ──────────── │ │
│ │ │
│ ─────────────── /token + code_verifier ─┼────────────────────────────► │
│ │ │
│ │ Verify: SHA256(verifier) │
│ │ == challenge │
│ │ │
│ ◄───────────────────────────────────────┼─────── access_token ──────── │
│ │ │┌──────────┐ ┌──────────┐ ┌──────────┐
│ 客户端 │ │ Zoom │ │ Zoom │
│ 应用 │ │ 认证服务 │ │ 令牌服务 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ 1. 生成code_verifier(随机值) │ │
│ 2. 生成code_challenge = SHA256(verifier) │
│ │ │
│ ─────── /authorize + code_challenge ──► │ │
│ │ │
│ ◄────── authorization_code ──────────── │ │
│ │ │
│ ─────────────── /token + code_verifier ─┼────────────────────────────► │
│ │ │
│ │ 校验:SHA256(verifier) 等于 challenge │
│ │ │
│ ◄───────────────────────────────────────┼─────── access_token ──────── │
│ │ │Implementation (Node.js)
实现示例(Node.js)
javascript
const crypto = require('crypto');
function generatePKCE() {
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
return { verifier, challenge };
}
const pkce = generatePKCE();
const authUrl = `https://zoom.us/oauth/authorize?` +
`response_type=code&` +
`client_id=${CLIENT_ID}&` +
`redirect_uri=${REDIRECT_URI}&` +
`code_challenge=${pkce.challenge}&` +
`code_challenge_method=S256`;
// Store pkce.verifier in session for callbackjavascript
const crypto = require('crypto');
function generatePKCE() {
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
return { verifier, challenge };
}
const pkce = generatePKCE();
const authUrl = `https://zoom.us/oauth/authorize?` +
`response_type=code&` +
`client_id=${CLIENT_ID}&` +
`redirect_uri=${REDIRECT_URI}&` +
`code_challenge=${pkce.challenge}&` +
`code_challenge_method=S256`;
// 将pkce.verifier存储在session中供回调时使用Token Exchange with PKCE
带PKCE的令牌交换
bash
POST https://zoom.us/oauth/token?grant_type=authorization_code&code={CODE}&redirect_uri={REDIRECT_URI}&code_verifier={VERIFIER}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}bash
POST https://zoom.us/oauth/token?grant_type=authorization_code&code={CODE}&redirect_uri={REDIRECT_URI}&code_verifier={VERIFIER}
Headers:
Authorization: Basic {Base64(ClientID:ClientSecret)}Deauthorization
取消授权
When a user removes your app, Zoom sends a webhook to your Deauthorization Notification Endpoint URL.
当用户移除你的应用时,Zoom会向你的取消授权通知端点URL发送Webhook。
Webhook Event
Webhook事件
json
{
"event": "app_deauthorized",
"event_ts": 1740439732278,
"payload": {
"account_id": "ACCOUNT_ID",
"user_id": "USER_ID",
"signature": "SIGNATURE",
"deauthorization_time": "2019-06-17T13:52:28.632Z",
"client_id": "CLIENT_ID"
}
}json
{
"event": "app_deauthorized",
"event_ts": 1740439732278,
"payload": {
"account_id": "ACCOUNT_ID",
"user_id": "USER_ID",
"signature": "SIGNATURE",
"deauthorization_time": "2019-06-17T13:52:28.632Z",
"client_id": "CLIENT_ID"
}
}Requirements
要求
- Delete all associated user data after receiving this event
- Verify webhook signature (use secret token, verification token deprecated Oct 2023)
- Only public apps receive deauthorization webhooks (not private/dev apps)
- 收到该事件后删除所有关联的用户数据
- 验证Webhook签名(使用密钥令牌,验证令牌已于2023年10月废弃)
- 仅公开应用会收到取消授权Webhook(私有/开发应用不会)
Pre-Approval Flow
预审批流程
Some Zoom accounts require Marketplace admin pre-approval before users can authorize apps.
- Users can request pre-approval from their admin
- Account-level apps (admin scopes) require appropriate role permissions
部分Zoom账户要求市场管理员预审批后,用户才能授权应用。
- 用户可以向管理员申请预审批
- 账户级应用(管理员作用域)需要对应的角色权限
Active Apps Notifier (AAN)
活跃应用通知(AAN)
In-meeting feature showing apps with real-time access to content.
- Displays icon + tooltip with app info, content type being accessed, approving account
- Supported: Zoom client 5.6.7+, Meeting SDK 5.9.0+
会议内功能,展示可实时访问内容的应用。
- 展示图标+提示框,包含应用信息、访问的内容类型、审批账户
- 支持版本:Zoom客户端5.6.7+、Meeting SDK 5.9.0+
OAuth Scopes
OAuth作用域
Scope Types
作用域类型
| Type | Description | For |
|---|---|---|
| Classic scopes | Legacy scopes (user, admin, master levels) | Existing apps |
| Granular scopes | New fine-grained scopes with optional support | New apps |
| 类型 | 说明 | 适用场景 |
|---|---|---|
| 经典作用域 | 旧版作用域(用户、管理员、主账户级别) | 现有应用 |
| 细粒度作用域 | 新增的细粒度作用域,支持可选授权 | 新应用 |
Classic Scopes
经典作用域
For previously-created apps. Three levels:
- User-level: Access to individual user's data
- Admin-level: Account-wide access, requires admin role
- Master-level: For master-sub account setups, requires account owner
适用于之前创建的应用,分为三个级别:
- 用户级:访问单个用户的数据
- 管理员级:全账户访问,需要管理员角色
- 主账户级:适用于主-子账户架构,需要账户所有者权限
Granular Scopes
细粒度作用域
For new apps. Format:
<service>:<action>:<data_claim>:<access>| Component | Values |
|---|---|
| service | |
| action | |
| data_claim | Data category (e.g., |
| access | empty (user), |
Example:
meeting:read:list_meetings:admin适用于新应用,格式:
<服务>:<操作>:<数据项>:<访问级别>| 组成部分 | 取值示例 |
|---|---|
| 服务 | |
| 操作 | |
| 数据项 | 数据类别(例如 |
| 访问级别 | 空(用户级)、 |
示例:
meeting:read:list_meetings:adminOptional Scopes
可选作用域
Granular scopes can be marked as optional - users choose whether to grant them.
Basic authorization (uses build flow defaults):
https://zoom.us/oauth/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}Advanced authorization (custom scopes per request):
https://zoom.us/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={required_scopes}&optional_scope={optional_scopes}Include previously granted scopes:
https://zoom.us/oauth/authorize?...&include_granted_scopes&scope={additional_scopes}细粒度作用域可以标记为可选,用户可以自主选择是否授权。
基础授权(使用构建流程默认配置):
https://zoom.us/oauth/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}高级授权(按请求自定义作用域):
https://zoom.us/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={required_scopes}&optional_scope={optional_scopes}包含之前已授权的作用域:
https://zoom.us/oauth/authorize?...&include_granted_scopes&scope={additional_scopes}Migrating Classic to Granular
经典作用域迁移到细粒度作用域
- Manage > select app > edit
- Scope page > Development tab > click Migrate
- Review auto-assigned granular scopes, remove unnecessary, mark optional
- Test
- Production tab > click Migrate
Notes:
- No review needed if only migrating or reducing scopes
- Existing user tokens continue with classic scope values until re-authorization
- New users get granular scopes after migration
- 管理 > 选择应用 > 编辑
- 作用域页面 > 开发选项卡 > 点击迁移
- 检查自动分配的细粒度作用域,移除不需要的项,标记可选作用域
- 测试
- 生产选项卡 > 点击迁移
注意:
- 仅迁移或减少作用域无需重新审核
- 现有用户令牌在重新授权前将继续使用经典作用域值
- 迁移后新用户将获取细粒度作用域
Common Error Codes
常见错误码
| Code | Message | Solution |
|---|---|---|
| 4700 | Token cannot be empty | Check Authorization header has valid token |
| 4702/4704 | Invalid client | Verify Client ID and Client Secret |
| 4705 | Grant type not supported | Use: |
| 4706 | Client ID or secret missing | Add credentials to header or request params |
| 4709 | Redirect URI mismatch | Ensure redirect_uri matches app configuration exactly (including trailing slash) |
| 4711 | Refresh token invalid | Token scopes don't match client scopes |
| 4717 | App has been disabled | Contact Zoom support |
| 4733 | Code is expired | Authorization codes expire in 5 minutes - restart flow |
| 4734 | Invalid authorization code | Regenerate authorization code |
| 4735 | Owner of token does not exist | User was removed from account - re-authorize |
| 4741 | Token has been revoked | Use the most recent token from latest authorization |
See for complete error list.
references/oauth-errors.md| 错误码 | 消息 | 解决方案 |
|---|---|---|
| 4700 | 令牌不能为空 | 检查Authorization头是否包含有效令牌 |
| 4702/4704 | 客户端无效 | 验证Client ID和Client Secret是否正确 |
| 4705 | 不支持的授权类型 | 使用以下授权类型: |
| 4706 | 缺少Client ID或密钥 | 在请求头或参数中添加凭证 |
| 4709 | 重定向URI不匹配 | 确保redirect_uri与应用配置完全一致(包括末尾斜杠) |
| 4711 | 刷新令牌无效 | 令牌作用域与客户端作用域不匹配 |
| 4717 | 应用已被禁用 | 联系Zoom支持 |
| 4733 | 授权码已过期 | 授权码有效期为5分钟,重启授权流程 |
| 4734 | 授权码无效 | 重新生成授权码 |
| 4735 | 令牌所有者不存在 | 用户已从账户中移除,需要重新授权 |
| 4741 | 令牌已被吊销 | 使用最新授权生成的最新令牌 |
完整错误列表请查看。
references/oauth-errors.mdQuick Reference
快速参考
| Flow | Grant Type | Token Expiry | Refresh |
|---|---|---|---|
| Account (S2S) | | 1 hour | Request new token |
| User | | 1 hour | Use refresh_token (90 day expiry) |
| Device | | 1 hour | Use refresh_token (90 day expiry) |
| Client (Chatbot) | | 1 hour | Request new token |
| 流程 | Grant Type | 令牌有效期 | 刷新方式 |
|---|---|---|---|
| 账户授权(S2S) | | 1小时 | 请求新令牌 |
| 用户授权 | | 1小时 | 使用refresh_token(有效期90天) |
| 设备授权 | | 1小时 | 使用refresh_token(有效期90天) |
| 客户端授权(聊天机器人) | | 1小时 | 请求新令牌 |
Demo Guidance
演示应用指南
If you build an OAuth demo app, document its runtime base URL in that demo project's own
README or , not in this shared skill.
.env.example如果你构建了OAuth演示应用,请将运行时基础URL记录在演示项目自身的README或中,不要写在本共享技能文档中。
.env.exampleResources
资源
- OAuth docs: https://developers.zoom.us/docs/integrations/oauth/
- S2S OAuth docs: https://developers.zoom.us/docs/internal-apps/s2s-oauth/
- PKCE blog: https://developers.zoom.us/blog/pcke-oauth-with-postman-rest-api/
- Classic scopes: https://developers.zoom.us/docs/integrations/oauth-scopes/
- Granular scopes: https://developers.zoom.us/docs/integrations/oauth-scopes-granular/
- OAuth文档:https://developers.zoom.us/docs/integrations/oauth/
- S2S OAuth文档:https://developers.zoom.us/docs/internal-apps/s2s-oauth/
- PKCE博客:https://developers.zoom.us/blog/pcke-oauth-with-postman-rest-api/
- 经典作用域:https://developers.zoom.us/docs/integrations/oauth-scopes/
- 细粒度作用域:https://developers.zoom.us/docs/integrations/oauth-scopes-granular/
Integrated Index
集成索引
This section was migrated from .
SKILL.md本部分从迁移而来。
SKILL.mdQuick Start Path
快速入门路径
If you're new to Zoom OAuth, follow this order:
-
Run preflight checks first → RUNBOOK.md
-
Choose your OAuth flow → concepts/oauth-flows.md
- 4 flows: S2S (backend), User (SaaS), Device (no browser), Chatbot
- Decision matrix: Which flow fits your use case?
-
Understand token lifecycle → concepts/token-lifecycle.md
- CRITICAL: How tokens expire, refresh, and revoke
- Common pitfalls: refresh token rotation
-
Implement your flow → Jump to examples:
- Backend automation → examples/s2s-oauth-redis.md
- SaaS app → examples/user-oauth-mysql.md
- Mobile/SPA → examples/pkce-implementation.md
- Device (TV/kiosk) → examples/device-flow.md
-
Fix redirect URI issues → troubleshooting/redirect-uri-issues.md
- Most common OAuth error: Redirect URI mismatch
-
Implement token refresh → examples/token-refresh.md
- Automatic middleware pattern
- Handle refresh token rotation
-
Troubleshoot errors → troubleshooting/common-errors.md
- Error code tables (4700-4741 range)
- Quick diagnostic workflow
如果你是Zoom OAuth新手,请按以下顺序学习:
-
首先运行预检检查 → RUNBOOK.md
-
选择你的OAuth流程 → concepts/oauth-flows.md
- 4种流程:S2S(后端)、用户(SaaS)、设备(无浏览器)、聊天机器人
- 决策矩阵:匹配你的使用场景的最优流程
-
理解令牌生命周期 → concepts/token-lifecycle.md
- 关键:令牌过期、刷新和吊销规则
- 常见陷阱:刷新令牌轮换
-
实现你的流程 → 跳转到对应示例:
- 后端自动化 → examples/s2s-oauth-redis.md
- SaaS应用 → examples/user-oauth-mysql.md
- 移动端/SPA → examples/pkce-implementation.md
- 设备(电视/自助终端)→ examples/device-flow.md
-
修复重定向URI问题 → troubleshooting/redirect-uri-issues.md
- 最常见的OAuth错误:重定向URI不匹配
-
实现令牌刷新 → examples/token-refresh.md
- 自动中间件模式
- 处理刷新令牌轮换
-
排查错误 → troubleshooting/common-errors.md
- 错误码表(4700-4741范围)
- 快速诊断流程
Documentation Structure
文档结构
oauth/
├── SKILL.md # Main skill overview
├── SKILL.md # This file - navigation guide
│
├── concepts/ # Core OAuth concepts
│ ├── oauth-flows.md # 4 flows: S2S, User, Device, Chatbot
│ ├── token-lifecycle.md # Expiration, refresh, revocation
│ ├── pkce.md # PKCE security for public clients
│ ├── scopes-architecture.md # Classic vs Granular scopes
│ └── state-parameter.md # CSRF protection with state
│
├── examples/ # Complete working code
│ ├── s2s-oauth-basic.md # S2S OAuth minimal example
│ ├── s2s-oauth-redis.md # S2S OAuth with Redis caching (production)
│ ├── user-oauth-basic.md # User OAuth minimal example
│ ├── user-oauth-mysql.md # User OAuth with MySQL + encryption (production)
│ ├── device-flow.md # Device authorization flow
│ ├── pkce-implementation.md # PKCE for SPAs/mobile apps
│ └── token-refresh.md # Auto-refresh middleware pattern
│
├── troubleshooting/ # Problem solving guides
│ ├── common-errors.md # Error codes 4700-4741
│ ├── redirect-uri-issues.md # Most common OAuth error
│ ├── token-issues.md # Expired, revoked, invalid tokens
│ └── scope-issues.md # Scope mismatch errors
│
└── references/ # Reference documentation
├── oauth-errors.md # Complete error code reference
├── classic-scopes.md # Classic scope reference
└── granular-scopes.md # Granular scope referenceoauth/
├── SKILL.md # 技能总览
├── SKILL.md # 本文件 - 导航指南
│
├── concepts/ # 核心OAuth概念
│ ├── oauth-flows.md # 4种流程:S2S、用户、设备、聊天机器人
│ ├── token-lifecycle.md # 过期、刷新、吊销
│ ├── pkce.md # 公开客户端的PKCE安全机制
│ ├── scopes-architecture.md # 经典作用域 vs 细粒度作用域
│ └── state-parameter.md # 使用state参数的CSRF防护
│
├── examples/ # 完整可运行代码
│ ├── s2s-oauth-basic.md # S2S OAuth最小示例
│ ├── s2s-oauth-redis.md # 带Redis缓存的S2S OAuth(生产级)
│ ├── user-oauth-basic.md # 用户OAuth最小示例
│ ├── user-oauth-mysql.md # 带MySQL+加密的用户OAuth(生产级)
│ ├── device-flow.md # 设备授权流程
│ ├── pkce-implementation.md # 适用于SPA/移动应用的PKCE实现
│ └── token-refresh.md # 自动刷新中间件模式
│
├── troubleshooting/ # 问题排查指南
│ ├── common-errors.md # 4700-4741错误码
│ ├── redirect-uri-issues.md # 最常见的OAuth错误
│ ├── token-issues.md # 过期、吊销、无效令牌问题
│ └── scope-issues.md # 作用域不匹配错误
│
└── references/ # 参考文档
├── oauth-errors.md # 完整错误码参考
├── classic-scopes.md # 经典作用域参考
└── granular-scopes.md # 细粒度作用域参考By Use Case
按使用场景分类
I want to automate Zoom tasks on my own account
我要自动化自有账户的Zoom任务
- OAuth Flows - S2S OAuth explained
- S2S OAuth Redis - Production pattern with Redis caching
- Token Lifecycle - 1hr token, no refresh
- OAuth流程 - S2S OAuth说明
- S2S OAuth Redis示例 - 带Redis缓存的生产模式
- 令牌生命周期 - 1小时令牌有效期,无刷新流程
I want to build a SaaS app for other Zoom users
我要为其他Zoom用户构建SaaS应用
- OAuth Flows - User OAuth explained
- User OAuth MySQL - Production pattern with encryption
- Token Refresh - Automatic refresh middleware
- Redirect URI Issues - Fix most common error
- OAuth流程 - 用户OAuth说明
- 用户OAuth MySQL示例 - 带加密的生产模式
- 令牌刷新 - 自动刷新中间件
- 重定向URI问题 - 修复最常见错误
I want to build a mobile or SPA app
我要构建移动或SPA应用
- PKCE - Why PKCE is required for public clients
- PKCE Implementation - Complete code example
- State Parameter - CSRF protection
- PKCE - 为什么公开客户端必须使用PKCE
- PKCE实现示例 - 完整代码示例
- State参数 - CSRF防护
I want to build an app for devices without browsers (TV, kiosk)
我要为无浏览器的设备(电视、自助终端)构建应用
- OAuth Flows - Device flow explained
- Device Flow Example - Complete polling implementation
- Common Errors - Device-specific errors
- OAuth流程 - 设备流程说明
- 设备流程示例 - 完整轮询实现
- 常见错误 - 设备相关错误
I'm building a Team Chat bot
我要构建团队聊天机器人
- OAuth Flows - Chatbot flow explained
- S2S OAuth Basic - Similar pattern, different grant type
- Scopes Architecture - Chatbot-specific scopes
- OAuth流程 - 聊天机器人流程说明
- S2S OAuth基础示例 - 类似模式,不同授权类型
- 作用域架构 - 聊天机器人专属作用域
I'm getting redirect URI errors (4709)
我遇到重定向URI错误(4709)
- Redirect URI Issues - START HERE!
- Common Errors - Error details
- User OAuth Basic - See correct pattern
- 重定向URI问题 - 从这里开始排查!
- 常见错误 - 错误详情
- 用户OAuth基础示例 - 查看正确实现模式
I'm getting token errors (4700-4741)
我遇到令牌错误(4700-4741)
- Token Issues - Diagnostic workflow
- Token Lifecycle - Understand expiration
- Token Refresh - Implement auto-refresh
- Common Errors - Error code tables
- 令牌问题 - 诊断流程
- 令牌生命周期 - 理解过期规则
- 令牌刷新 - 实现自动刷新
- 常见错误 - 错误码表
I'm getting scope errors (4711)
我遇到作用域错误(4711)
- Scope Issues - Mismatch causes
- Scopes Architecture - Classic vs Granular
- Classic Scopes - Complete scope reference
- Granular Scopes - Granular scope reference
- 作用域问题 - 不匹配原因
- 作用域架构 - 经典 vs 细粒度作用域
- 经典作用域 - 完整作用域参考
- 细粒度作用域 - 细粒度作用域参考
I need to refresh tokens
我需要实现令牌刷新
- Token Lifecycle - When to refresh
- Token Refresh - Middleware pattern
- Token Issues - Common mistakes
- 令牌生命周期 - 刷新时机
- 令牌刷新 - 中间件模式
- 令牌问题 - 常见错误
I want to understand the difference between Classic and Granular scopes
我想了解经典和细粒度作用域的区别
- Scopes Architecture - Complete comparison
- Classic Scopes - format
resource:level - Granular Scopes - format
service:action:data_claim:access
- 作用域架构 - 完整对比
- 经典作用域 - 格式
resource:level - 细粒度作用域 - 格式
service:action:data_claim:access
I need to secure my OAuth implementation
我需要加固OAuth实现的安全性
- PKCE - Public client security
- State Parameter - CSRF protection
- User OAuth MySQL - Token encryption at rest
- PKCE - 公开客户端安全
- State参数 - CSRF防护
- 用户OAuth MySQL示例 - 静态令牌加密
I want to migrate from JWT app to S2S OAuth
我要从JWT应用迁移到S2S OAuth
- S2S OAuth Redis - Modern replacement
- Token Lifecycle - Different token behavior
Note: JWT App Type was deprecated in June 2023. Migrate to S2S OAuth for server-to-server automation.
- S2S OAuth Redis示例 - 现代替代方案
- 令牌生命周期 - 不同的令牌行为
注意:JWT应用类型已于2023年6月废弃,服务端到服务端自动化场景请迁移到S2S OAuth。
Most Critical Documents
最重要的文档
1. OAuth Flows (DECISION DOCUMENT)
1. OAuth流程(决策文档)
concepts/oauth-flows.md
Understand which of the 4 flows to use:
- S2S OAuth: Backend automation (your account)
- User OAuth: SaaS apps (users authorize you)
- Device Flow: Devices without browsers
- Chatbot: Team Chat bots only
concepts/oauth-flows.md
了解4种流程的适用场景:
- S2S OAuth:后端自动化(自有账户)
- 用户OAuth:SaaS应用(用户授权访问)
- 设备流程:无浏览器的设备
- 聊天机器人:仅团队聊天机器人场景
2. Token Lifecycle (MOST COMMON ISSUE)
2. 令牌生命周期(最常见问题来源)
concepts/token-lifecycle.md
99% of OAuth issues stem from misunderstanding:
- Token expiration (1 hour for all flows)
- Refresh token rotation (must save new refresh token)
- Revocation behavior (invalidates all tokens)
concepts/token-lifecycle.md
99%的OAuth问题都源于对以下内容的误解:
- 令牌过期(所有流程的访问令牌有效期都是1小时)
- 刷新令牌轮换(必须保存新的刷新令牌)
- 吊销行为(会使所有令牌失效)
3. Redirect URI Issues (MOST COMMON ERROR)
3. 重定向URI问题(最常见错误)
troubleshooting/redirect-uri-issues.md
Error 4709 ("Redirect URI mismatch") is the #1 OAuth error.
Must match EXACTLY (including trailing slash, http vs https).
troubleshooting/redirect-uri-issues.md
错误4709(「重定向URI不匹配」)是排名第一的OAuth错误,必须与配置完全一致(包括末尾斜杠、http/https协议)。
Key Learnings
核心要点
Critical Discoveries:
关键发现:
-
Refresh Token Rotation
- Each refresh returns a NEW refresh token
- Old refresh token becomes invalid
- Failure to save new token causes 4735 errors
- See: Token Refresh
-
S2S OAuth Uses Redis, User OAuth Uses Database
- S2S: Single token for entire account → Redis (ephemeral)
- User: Per-user tokens → Database (persistent)
- See: S2S OAuth Redis vs User OAuth MySQL
-
Redirect URI Must Match EXACTLY
- Trailing slash matters: ≠
/callback/callback/ - Protocol matters: ≠
http://https:// - Port matters: ≠
:3000:3001 - See: Redirect URI Issues
- Trailing slash matters:
-
PKCE Required for Public Clients
- Mobile apps CANNOT keep secrets
- SPAs CANNOT keep secrets
- PKCE prevents authorization code interception
- See: PKCE
-
State Parameter Prevents CSRF
- Generate random state before redirect
- Store in session
- Verify on callback
- See: State Parameter
-
Token Storage Must Be Encrypted
- NEVER store tokens in plain text
- Use AES-256 minimum
- See: User OAuth MySQL
-
JWT App Type is Deprecated (June 2023)
- No new JWT apps can be created
- Existing apps still work but will eventually be sunset
- Migrate to S2S OAuth or User OAuth
-
Scope Levels Determine Authorization Requirements
- No suffix (user-level): Any user can authorize
- : Requires admin role
:admin - : Requires account owner (multi-account)
:master - See: Scopes Architecture
-
Authorization Codes Expire in 5 Minutes
- Exchange code for token immediately
- Don't cache authorization codes
- See: Token Lifecycle
-
Device Flow Requires Polling
- Poll at interval returned by (usually 5s)
/devicecode - Handle ,
authorization_pending,slow_downexpired_token - See: Device Flow
- Poll at interval returned by
-
刷新令牌轮换
- 每次刷新都会返回一个新的刷新令牌
- 旧的刷新令牌会失效
- 未保存新令牌会导致4735错误
- 参考:令牌刷新
-
S2S OAuth使用Redis,用户OAuth使用数据库
- S2S:全账户共用单个令牌 → Redis(临时存储)
- 用户:每个用户单独的令牌 → 数据库(持久存储)
- 参考:S2S OAuth Redis示例 对比 用户OAuth MySQL示例
-
重定向URI必须完全匹配
- 末尾斜杠会影响匹配:≠
/callback/callback/ - 协议会影响匹配:≠
http://https:// - 端口会影响匹配:≠
:3000:3001 - 参考:重定向URI问题
- 末尾斜杠会影响匹配:
-
公开客户端必须使用PKCE
- 移动应用无法安全存储密钥
- SPA无法安全存储密钥
- PKCE可防止授权码被拦截
- 参考:PKCE
-
State参数可防止CSRF
- 重定向前生成随机state
- 存储在session中
- 回调时验证state
- 参考:State参数
-
令牌存储必须加密
- 永远不要明文存储令牌
- 最低使用AES-256加密
- 参考:用户OAuth MySQL示例
-
JWT应用类型已废弃(2023年6月)
- 无法创建新的JWT应用
- 现有应用仍可使用但最终会停止支持
- 请迁移到S2S OAuth或用户OAuth
-
作用域级别决定授权要求
- 无后缀(用户级):任意用户可授权
- :需要管理员角色
:admin - :需要账户所有者(多账户场景)
:master - 参考:作用域架构
-
授权码有效期为5分钟
- 收到授权码后立即交换令牌
- 不要缓存授权码
- 参考:令牌生命周期
-
设备流程需要轮询
- 按返回的间隔轮询(通常为5秒)
/devicecode - 处理、
authorization_pending、slow_down状态expired_token - 参考:设备流程
- 按
Quick Reference
快速查询
"Which OAuth flow should I use?"
「我应该使用哪种OAuth流程?」
→ OAuth Flows
→ OAuth流程
"Redirect URI mismatch error (4709)"
「重定向URI不匹配错误(4709)」
→ Redirect URI Issues
→ 重定向URI问题
"Token expired or invalid"
「令牌过期或无效」
→ Token Issues
→ 令牌问题
"Refresh token invalid (4735)"
「刷新令牌无效(4735)」
→ Token Refresh - Must save new refresh token
→ 令牌刷新 - 必须保存新的刷新令牌
"Scope mismatch error (4711)"
「作用域不匹配错误(4711)」
→ Scope Issues
→ 作用域问题
"How do I secure my OAuth app?"
「如何加固OAuth应用的安全性?」
→ PKCE + State Parameter
→ PKCE + State参数
"How do I implement auto-refresh?"
「如何实现自动刷新?」
→ Token Refresh
→ 令牌刷新
"What's the difference between Classic and Granular scopes?"
「经典和细粒度作用域有什么区别?」
→ Scopes Architecture
→ 作用域架构
"What error code means what?"
「错误码对应的含义是什么?」
→ Common Errors
→ 常见错误
Document Version
文档版本
Based on Zoom OAuth API v2 (2024+)
Deprecated: JWT App Type (June 2023)
Happy coding!
Remember: Start with OAuth Flows to understand which flow fits your use case!
基于Zoom OAuth API v2(2024+版本)
已废弃: JWT应用类型(2023年6月)
编码愉快!
记住:首先查看OAuth流程,了解哪种流程适合你的使用场景!
Environment Variables
环境变量
- See references/environment-variables.md for standardized keys and where to find each value.
.env
标准化的键名及取值获取方式请参考references/environment-variables.md。
.env