Zoom Meeting SDKをWebアプリに組み込むビデオ会議連携入門

概要

自社サービスの画面内でそのままビデオ会議を開きたい、というニーズは意外と多くあります。オンライン診療、オンライン家庭教師、商談、カスタマーサポートなど、「別アプリに飛ばさず、自分たちのWebアプリの中で会議を完結させたい」というケースです。

これを実現する手段のひとつが Zoom Meeting SDK です。本記事では、Zoom Meeting SDK(Web向け)をWebアプリに組み込む最小構成を、公開ドキュメントに基づいてハンズオン形式でまとめます。

ゴールは次の3つです。

  • Zoom Marketplace で Meeting SDK 用アプリを作る
  • サーバ側で参加用の署名(JWT)を発行する
  • フロント側(Component View)で会議に参加する

> 本記事のコードは解説用の最小構成です。本番導入時は認証・エラーハンドリング・利用規約まわりを別途設計してください。

環境

  • Node.js 18 以降
  • フロント: React + TypeScript(プレーンなJSでも可)
  • Zoom Meeting SDK: @zoom/meetingsdk
  • サーバ(署名発行用): Node.js + Express + jsonwebtoken

Zoom の Web 向け SDK には描画方式が2つあります。

方式 特徴 向いている用途
Client View Zoom純正に近いフルUI。画面をほぼ占有 Zoomと同等の体験を出したい
Component View 任意のDOM要素に埋め込み。配置を制御しやすい 自社UIの一部として会議を置きたい

自社アプリに「溶け込ませる」なら Component View が扱いやすいため、本記事はこちらで進めます。

全体構成

ポイントは「署名をフロントで作らない」ことに尽きます。

[ブラウザ]
  │ 1. 会議番号などを渡して署名を要求
  ▼
[自前のバックエンド] ── SDK Secret を保持
  │ 2. JWT署名を生成して返す
  ▼
[ブラウザ]
  │ 3. 署名を使って Zoom の会議に参加
  ▼
[Zoom インフラ]

SDK Secret はクレデンシャルなので、ブラウザに置いた時点で漏洩します。署名の生成は必ずサーバ側で行います。

手順1: Zoom Marketplace でアプリを作る

  1. Zoom App Marketplace にサインイン
  2. 「Develop」→「Build App」から Meeting SDK タイプのアプリを作成
  3. 発行された Client ID / Client Secret(SDK Key / SDK Secret に相当)を控える

この Client ID / Client Secret が署名生成のキーになります。環境変数に入れておきます。

# .env(コミットしない)
ZOOM_SDK_KEY=your_client_id
ZOOM_SDK_SECRET=your_client_secret

手順2: サーバ側で署名(JWT)を発行する

Meeting SDK の参加署名は HS256 の JWT です。ペイロードに会議番号・ロール・有効期限を入れ、SDK Secret で署名します。

// server/signature.js
const jwt = require('jsonwebtoken')

/**
 * @param {string|number} meetingNumber 会議番号
 * @param {number} role 0=参加者, 1=ホスト
 */
function generateSignature(meetingNumber, role) {
  const iat = Math.round(Date.now() / 1000) - 30 // 時刻ずれ対策で30秒戻す
  const exp = iat + 60 * 60 * 2 // 2時間
  const header = { alg: 'HS256', typ: 'JWT' }

  const payload = {
    appKey: process.env.ZOOM_SDK_KEY,
    sdkKey: process.env.ZOOM_SDK_KEY,
    mn: meetingNumber,
    role,
    iat,
    exp,
    tokenExp: exp,
  }

  return jwt.sign(payload, process.env.ZOOM_SDK_SECRET, {
    algorithm: 'HS256',
    header,
  })
}

module.exports = { generateSignature }

これを API として露出します。

// server/index.js
const express = require('express')
const cors = require('cors')
const { generateSignature } = require('./signature')

const app = express()
app.use(cors())
app.use(express.json())

app.post('/api/zoom/signature', (req, res) => {
  const { meetingNumber, role = 0 } = req.body

  if (!meetingNumber) {
    return res.status(400).json({ error: 'meetingNumber is required' })
  }

  // 実運用ではここでログイン状態・会議参加権限を検証する
  const signature = generateSignature(meetingNumber, role)
  res.json({ signature, sdkKey: process.env.ZOOM_SDK_KEY })
})

app.listen(4000, () => console.log('signature server on :4000'))

> ⚠️ /api/zoom/signature を認証なしで公開すると、誰でも任意の会議番号の署名を発行できてしまいます。必ずログイン・権限チェックを前段に挟んでください。

手順3: フロント側で会議に参加する(Component View)

まずパッケージを入れます。

npm install @zoom/meetingsdk

Component View のエントリは @zoom/meetingsdk/embedded の ZoomMtgEmbedded です。会議を描画する空のDOM要素を用意し、init → join の順で呼びます。

// src/ZoomMeeting.tsx
import { useRef } from 'react'
import ZoomMtgEmbedded from '@zoom/meetingsdk/embedded'

const SIGNATURE_ENDPOINT = 'http://localhost:4000/api/zoom/signature'

export function ZoomMeeting() {
  const rootRef = useRef<HTMLDivElement>(null)

  const join = async () => {
    const meetingNumber = '1234567890' // 実際は入力/APIから取得
    const password = ''                // 会議パスコード
    const userName = 'Guest User'

    // 1. 署名をサーバから取得
    const res = await fetch(SIGNATURE_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ meetingNumber, role: 0 }),
    })
    const { signature, sdkKey } = await res.json()

    // 2. クライアント初期化
    const client = ZoomMtgEmbedded.createClient()
    await client.init({
      zoomAppRoot: rootRef.current!,
      language: 'en-US',
      patchJsMedia: true, // メディア周りの互換パッチを有効化
    })

    // 3. 会議に参加
    await client.join({
      signature,
      sdkKey,
      meetingNumber,
      password,
      userName,
    })
  }

  return (
    <div>
      <button onClick={join}>会議に参加</button>
      {/* Zoom がこの要素の中に会議UIを描画する */}
      <div ref={rootRef} style={{ width: 800, height: 600 }} />
    </div>
  )
}

これで「会議に参加」を押すと、指定したDOM要素の中にZoomの会議UIが埋め込まれます。

確認方法

  1. 署名発行サーバを起動する(node server/index.js)
  2. フロントを起動し、有効な会議番号(自分で作ったテスト会議でよい)を指定する
  3. ボタン押下でブラウザ内に会議UIが表示され、映像・音声がつながるかを確認する
  4. ブラウザのネットワークタブで /api/zoom/signature が 200 を返しているか、署名が JWT 形式(xxxxx.yyyyy.zzzzz)になっているかを確認する

署名が不正な場合、join が拒否されます。JWT をデコードして mn(会議番号)・role・exp が意図どおりかを見ると、切り分けが早くなります。

注意点

1. SDK Secret をフロントに置かない 署名はサーバ生成が鉄則です。ビルド成果物に Secret が混入していないか必ず確認します。

2. 時刻ずれで署名が弾かれる iat を少し過去にずらすのは、クライアントとサーバの時刻ずれで「未来の署名」と判定されるのを防ぐための定番対策です。有効期限 exp が短すぎると会議中に切れるので注意します。

3. ブラウザ要件とHTTPS カメラ・マイクを使うため、ローカル以外では HTTPS が実質必須です。対応ブラウザも公式ドキュメントで確認しておきます。

4. Client View は事前ロードが必要 本記事は Component View 中心ですが、Client View(ZoomMtg)を使う場合は CDN アセットの指定や WASM の事前ロードなど追加手順があります。方式ごとに手順が違う点に注意します。

5. バージョン差異 Zoom SDK は更新が速く、関数名やオプション(例: patchJsMedia)が変わることがあります。導入時はインストールしたバージョンの公式ドキュメントを一次情報として参照してください。

まとめ

  • Zoom Meeting SDK を使えば、自社WebアプリにビデオをUIごと埋め込めます
  • 肝は「署名はサーバで作り、Secret をフロントに出さない」こと
  • 自社UIに溶け込ませたいなら Component View、Zoom純正体験なら Client View
  • 最小構成は「Marketplaceでアプリ作成 → サーバで署名発行 → フロントで init/join」の3ステップ

まずはテスト会議でこの3ステップを通すと、全体像が一気につかめます。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。