I am currently developing a platform where students can book classes with coaches. Upon booking, a Zoom meeting is created using a main Zoom account. The flow is as follows:
- Class Booking: A student books a class with a coach.
- Meeting Creation: A Zoom meeting is created using a main Zoom account via the Zoom API.
- Meeting Start: The meeting is started successfully on the frontend using the Zoom Meeting SDK.
- Meeting End: When trying to end the meeting, an
INSUFFICIENT_PRIVILEGESerror is encountered.
Implementation Details:
Frontend Code:
import React, { useEffect } from ‘react’;
import { ZoomMtgEmbedded } from ‘@zoomus/websdk/embedded’;
const ZoomMeetingComponent = () => {
const client = ZoomMtgEmbedded.createClient();
useEffect(() => {
const meetConfig = {
apiKey: ‘YOUR_API_KEY’,
signature: ‘YOUR_HOST_SIGNATURE’, // Ensure this signature is generated with role 1
meetingNumber: ‘YOUR_MEETING_NUMBER’,
userName: ‘YOUR_USER_NAME’,
passWord: ‘YOUR_PASSWORD’,
role: 1, // Ensure role is 1 for host
leaveUrl: ‘YOUR_LEAVE_URL’,
webEndpoint: ‘’
};
client.init({
debug: true,
zoomAppRoot: document.getElementById('zoom-meeting-container'),
language: 'en-US',
assetPath: '',
webEndpoint: meetConfig.webEndpoint,
});
client.join({
apiKey: meetConfig.apiKey,
signature: meetConfig.signature,
meetingNumber: meetConfig.meetingNumber,
password: meetConfig.passWord,
userName: meetConfig.userName,
});
}, );
const endMeeting = () => {
client.leaveMeeting({
success: function () {
console.log(‘Meeting ended successfully’);
},
error: function (error) {
console.error(‘End meeting error’, error);
}
});
};
return (
<div id=“zoom-meeting-container” style={{ width: ‘100%’, height: ‘100vh’ }}>
End Meeting
);
};
export default ZoomMeetingComponent;
Backend Code for Generating Signature:
async function generateZoomSignature (req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).send(sendResponse(1003, messages[1003], false, errors.errors));
}
try {
const { meetingNumber, role } = req.body;
const iat = Math.round((new Date().getTime() - 30000) / 1000);
const exp = iat + 60 * 60 * 2
const oHeader = { alg: ‘HS256’, typ: ‘JWT’ }
const oPayload = {
sdkKey: config.zoomMeetingSdkClientId,
mn: meetingNumber,
role: role,
iat: iat,
exp: exp,
tokenExp: exp
}
const sHeader = JSON.stringify(oHeader)
const sPayload = JSON.stringify(oPayload)
const sdkJWT = jwt.sign(sPayload, config.zoomMeetingSdkClientSecret, { header: oHeader });
return res.send(sendResponse(1097, messages[1101], true, { signature: sdkJWT } ));
} catch (error) {
console.error(‘Error handling Zoom webhook event:’, error);
return res.status(500).send(sendResponse(1000, messages[1000], false));
}
}
Issue:
I am able to start the meeting successfully with the Zoom Meeting SDK, but when attempting to end the meeting, I receive the following error:
{type: ‘IMPROPER_MEETING_STATE’, reason: ‘closed’}
Context:
- I have a main Zoom account from which all meetings are created.
- The coach, who is starting the meeting, is not the same user who created the meeting.
- I have also created a Zoom Meeting SDK account and use that account’s ID to start the meeting.
Question: Is this error occurring because the main host is a different user from the coach who is trying to end the meeting? If so, what is the recommended approach to resolve this issue? Can the host role be transferred programmatically, or is there another way to grant the necessary privileges to the coach?
Any guidance or suggestions on how to address this issue would be greatly appreciated.