You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zoom API创建会议遇401未授权问题及动态令牌授权咨询

问题根源与修复方案

核心错误点

  • 授权流程混乱:同时混用OAuth2的Authorization Code和Client Credentials两种流程,且/oauth/authorize接口需用GET请求而非POST——该接口是引导用户授权获取授权码的,不是通过POST直接获取授权状态。
  • Client Credentials令牌无用户上下文:用client_credentials获取的令牌属于应用级,未关联具体用户,无法调用/users/me/meetings接口,必须指定具体用户ID(如ops@supporthives.com)。
  • 会议时间格式错误:Zoom API要求start_time为ISO 8601 UTC格式(如2024-04-26T14:30:00Z),你用时间戳拼接的格式不符合要求。
  • 授权响应判断错误:if auth_response仅判断响应对象是否存在,无法正确识别授权是否成功,应检查响应状态码或返回内容。

正确实现方案

根据需求分两种场景给出代码:

场景1:服务端自动创建会议(Client Credentials流程)

适用于后台自动创建会议、无需用户手动授权的场景,前提是Zoom应用已配置Client Credentials权限,且目标用户已在Zoom平台存在。

import requests
from datetime import datetime, timezone

# 配置信息
ZOOM_CLIENT_ID = "你的Client ID"
ZOOM_CLIENT_SECRET = "你的Client Secret"
TARGET_USER_ID = "ops@supporthives.com"  # 必须指定具体用户ID

def get_access_token():
    """获取应用级访问令牌"""
    token_url = "https://zoom.us/oauth/token"
    params = {
        "grant_type": "client_credentials",
        "client_id": ZOOM_CLIENT_ID,
        "client_secret": ZOOM_CLIENT_SECRET
    }
    try:
        response = requests.post(token_url, params=params)
        response.raise_for_status()
        return response.json().get("access_token")
    except requests.RequestException as e:
        raise Exception(f"获取令牌失败: {str(e)}")

def create_zoom_meeting(event):
    """创建Zoom会议"""
    access_token = get_access_token()
    create_url = f"https://api.zoom.us/v2/users/{TARGET_USER_ID}/meetings"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }

    # 格式化会议时间为Zoom要求的ISO 8601 UTC格式
    event_datetime = datetime.combine(event.event_date, datetime.min.time()).replace(tzinfo=timezone.utc)
    start_time = event_datetime.isoformat().replace("+00:00", "Z")

    meeting_params = {
        "topic": event.event_title,
        "type": 2,  # 预约会议
        "start_time": start_time,
        "duration": 60,
        "timezone": "UTC",
        "description": event.event_description,
        "settings": {
            "host_video": True,
            "participant_video": True,
            "waiting_room": False,
            "join_before_host": True,
            "mute_upon_entry": False,
            "auto_recording": "none"
        }
    }

    try:
        response = requests.post(create_url, headers=headers, json=meeting_params)
        response.raise_for_status()
        meeting_data = response.json()
        event.event_link = meeting_data.get("join_url")
        event.event_meeting_data = meeting_data
        event.save()
        return meeting_data.get("join_url")
    except requests.RequestException as e:
        raise Exception(f"创建会议失败: {str(e)}")

场景2:用户授权后创建会议(Authorization Code流程)

适用于需要用户手动授权应用、之后代表用户创建会议的场景,需遵循完整的OAuth2授权流程:

import requests
from datetime import datetime, timezone
from urllib.parse import urlencode

ZOOM_CLIENT_ID = "你的Client ID"
ZOOM_CLIENT_SECRET = "你的Client Secret"
REDIRECT_URI = "https://gensproject.supporthives.com/zoom"

def get_authorization_url():
    """生成用户授权跳转URL"""
    auth_url = "https://zoom.us/oauth/authorize"
    params = {
        "client_id": ZOOM_CLIENT_ID,
        "response_type": "code",
        "redirect_uri": REDIRECT_URI,
        "scope": "meeting:write"  # 需提前申请该权限
    }
    return f"{auth_url}?{urlencode(params)}"

def exchange_code_for_token(code):
    """用授权码交换用户级访问令牌"""
    token_url = "https://zoom.us/oauth/token"
    params = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": REDIRECT_URI,
        "client_id": ZOOM_CLIENT_ID,
        "client_secret": ZOOM_CLIENT_SECRET
    }
    try:
        response = requests.post(token_url, params=params)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        raise Exception(f"令牌交换失败: {str(e)}")

def create_meeting_with_user_token(access_token, event):
    """使用用户令牌创建会议"""
    create_url = "https://api.zoom.us/v2/users/me/meetings"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }

    event_datetime = datetime.combine(event.event_date, datetime.min.time()).replace(tzinfo=timezone.utc)
    start_time = event_datetime.isoformat().replace("+00:00", "Z")

    meeting_params = {
        "topic": event.event_title,
        "type": 2,
        "start_time": start_time,
        "duration": 60,
        "timezone": "UTC",
        "description": event.event_description,
        "settings": {
            "host_video": True,
            "participant_video": True,
            "waiting_room": False,
            "join_before_host": True,
            "mute_upon_entry": False,
            "auto_recording": "none"
        }
    }

    try:
        response = requests.post(create_url, headers=headers, json=meeting_params)
        response.raise_for_status()
        meeting_data = response.json()
        event.event_link = meeting_data.get("join_url")
        event.event_meeting_data = meeting_data
        event.save()
        return meeting_data.get("join_url")
    except requests.RequestException as e:
        raise Exception(f"创建会议失败: {str(e)}")

额外注意事项

  • 确保Zoom应用已申请对应权限:创建会议需要meeting:write权限
  • 令牌有效期:两种流程的访问令牌有效期均为1小时,Authorization Code流程会返回刷新令牌用于续期
  • 生产环境需添加令牌缓存逻辑,避免重复请求令牌

内容的提问来源于stack exchange,提问作者Vishal Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:43:31