What I’m Trying to Achieve
- Register/login users via my custom backend.
- Create a Zoom meeting using the Zoom API.
- Start or join the meeting using the Zoom Meeting SDK in the browser.
Current Setup
Frontend (Next.js with Zoom Meeting SDK 3.12.0)
- I’m loading the Zoom Meeting SDK scripts dynamically and initializing it once loaded.
- Users can register/login, create a meeting, and attempt to start/join it.
- Relevant code snippet:
window.ZoomMtg.init({
leaveUrl: "***localhost:3000***",
isSupportAV: true,
success: () => {
window.ZoomMtg.join({
signature: meetingData.signature, // Fetched from backend
meetingNumber: meetingData.meetingNumber,
userName: formData.name || "Zoom User",
sdkKey: "UoCjUegUT16YHg1qRgb0Dg",
userEmail: formData.email || "zoomtest@test.com",
passWord: meetingData.password,
success: () => console.log("Joined meeting successfully"),
error: (err) => setError(err.message || "Failed to join meeting"),
});
},
error: (err) => setError(err.message || "Failed to initialize Zoom"),
});
SDK initialization:
useEffect(() => {
if (isSdkLoaded && window.ZoomMtg) {
window.ZoomMtg.setZoomJSLib("***//source.zoom.us/3.12.0/lib***", "/av");
window.ZoomMtg.preLoadWasm();
window.ZoomMtg.prepareWebSDK();
}
}, [isSdkLoaded]);
Backend (Laravel with Zoom API)
- I’m using the Zoom Server-to-Server OAuth flow to generate an access token and create meetings.
- I generate a signature for the Meeting SDK using JWT.
- Relevant code (ZoomService.php): php:
public function createMeeting(array $data): array {
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $this->getAccessToken(),
'Content-Type' => 'application/json',
])->post('***//api.zoom.us/v2/users/me/meetings***', [
'topic' => $data['title'],
'type' => 2,
'start_time' => Carbon::parse($data['start_time'])->toIso8601String(),
'duration' => $data['duration'],
'timezone' => $data['timezone'],
]);
return $response->json();
}
public function generateSignature(string $meetingNumber, int $role): string {
$sdkKey = env('ZOOM_CLIENT_ID');
$sdkSecret = env('ZOOM_CLIENT_SECRET');
$iat = time() - 30;
$exp = $iat + 60 * 60 * 2;
$payload = [
'sdkKey' => $sdkKey,
'mn' => $meetingNumber,
'role' => $role,
'iat' => $iat,
'exp' => $exp,
'tokenExp' => $exp,
];
return JWT::encode($payload, $sdkSecret, 'HS256');
}
The Issue
- I can successfully register/login and create a meeting (meeting ID is returned).
- However, when I attempt to start/join the meeting:
- The ZoomMtg.init callback fires successfully, but ZoomMtg.join throws an error like “invalid signature” error code “3172”.
- Logs show the signature and meeting data being fetched, but the meeting doesn’t launch in the browser.
What I’ve Tried
- Verified SDK Key, Client ID, Client Secret, and access token generation.
- Ensured the meeting ID and signature are correctly passed from backend to frontend.
- Tested with different roles (host=1, participant=0).
- Checked network requests—no obvious CORS or API errors.
Questions
- Is there an issue with how I’m initializing or using the Zoom Web API in Next.js?
- Could the signature generation on the backend be incorrect? Should ZOOM_CLIENT_ID be used as sdkKey, or do I need a separate SDK key?
- Are there any common pitfalls with Zoom Meeting SDK 3.12.0 that I might be missing?
Any help narrowing down whether this is a frontend, backend, or Zoom configuration issue would be greatly appreciated. I can provide more logs or details if needed. Thank you! Please note that all the url values here were modified removing https to be able to post