Sample code for nodejs with Zoom API / Zoom SDK

This is a sample code page for nodejs. It shows the common code sample when interacting with Zoom Webhook, Zoom Meeting SDK Auth Signature, Zoom OAuth and Zoom REST API.

Github Link

github source code

Live Demo



Code Samples

Tab 1 Content

   
 // Define a function to handle webhook requests
function handleWebhookRequest(req, res, secretToken, path) {


  if (req.method === 'POST') {
  // Check if the event type is "endpoint.url_validation"
  if (req.body.event === 'endpoint.url_validation') {
    const hashForValidate = crypto.createHmac('sha256', secretToken)
      .update(req.body.payload.plainToken)
      .digest('hex');

    res.status(200).json({
      "plainToken": req.body.payload.plainToken,
      "encryptedToken": hashForValidate
    });
  } else {


    res.status(200).send();
  }
}else if (req.method === 'GET') {



} else {
  // Handle unsupported HTTP methods
  res.status(405).send("Method Not Allowed");
}

}



app.post('/webhook/', (req, res) => {handleWebhookRequest(req,res, process.env.ZOOM_WEBHOOK_SECRET_TOKEN,"webhook");});
app.get('/webhook/', (req, res) => {handleWebhookRequest(req,res, process.env.ZOOM_WEBHOOK_SECRET_TOKEN,"webhook");});


Tab 2 Content

    
// Function to fetch a bearer token
async function fetchBearerToken() {
  try {
    // Create a Basic Authorization header with client credentials
    const credentials = Buffer.from(`${process.env.ZOOM_S2S_CLIENT_ID}:${process.env.ZOOM_S2S_CLIENT_SECRET}`).toString('base64');
    const apiUrl = `https://zoom.us/oauth/token?grant_type=account_credentials&account_id=${process.env.ZOOM_S2S_ACCOUNTID}`;
    
    // Define the token request parameters
    const tokenRequestData = {
      method: 'POST',
      url: apiUrl,
      headers: {
        'Authorization': `Basic ${credentials}`,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      
    };

    // Send the token request
    const response = await axios(tokenRequestData);

    // Extract the access token from the response
    const accessToken = response.data.access_token;
    // Return 
    return accessToken;
   
  } catch (error) {
    return error.message;
  }
}
    
    

Tab 3 Content

    

  // Define a function to handle the common logic for saving and retrieving data
function handleRedirectURLDataRequest(path, clientId,clientSecret, req, res){
  //post doesn't seem to be used
 var filename = "/var/www/asdc.cc/zoom-sdk-signature-generator/"+path+".txt"

  if (req.method === 'POST') {

    //handle get
  } else if (req.method === 'GET') {


    const codeFromQueryString = req.query.code; // Get the token from the query string

    if (codeFromQueryString && codeFromQueryString.length>=1){
    //get the request token from zoom's oauth


    const url = 'https://zoom.us/oauth/token';
    const data = {
      code: codeFromQueryString,
      grant_type: 'authorization_code',
      redirect_uri: 'https://asdc.cc/'+path
    };
    
    const headers = {
      Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,
      'Content-Type': 'application/x-www-form-urlencoded'
    };
    
    axios.post(url, new URLSearchParams(data).toString(), { headers })
      .then(response => {

        fs.writeFile(filename, JSON.stringify(response.data), 'utf8', function (err) {
          if (err) {
            return console.log(err);
          }
          console.log("The file was saved!");
        });

        console.log(response.data);
        res.status(200).json(response.data);
        // You can access the access_token in response.data.access_token
      })
      .catch(error => {
        console.error(error);
        res(error);
        // Handle any errors here
      });

    }
    //if there is no querystring entered
    else{
      fs.readFile(filename, 'utf8', (err, data) => {
        if (err) {
          return res.status(500).json({ error: 'Error reading file' });
        }
    
        try {
          // Parse the JSON data
          const jsonData = JSON.parse(data);
          // Send the JSON data as a response
          res.status(200).json(jsonData);
        } catch (parseError) {
          res.status(500).json({ error: 'Error parsing JSON data' });
        }
      });
  }
  }
}

// Define routes for different endpoints
app.post('/redirecturlformsdkoauth/', (req, res) => {
  var clientid=process.env.ZOOM_CLIENT_ID_NEW;
  var clientsecret=process.env.ZOOM_CLIENT_SECRET_NEW;
  handleRedirectURLDataRequest("redirecturlformsdkoauth",clientid,clientsecret, req, res);
});


Tab 4 Content

    
app.post('/meeting/', (req, res) => {

  const now = Math.round((new Date().getTime()) / 1000)
  //make it valid 5 minute ago
  const iat =now -  5 * 60;
    //make it expire 30 minutes later
    const exp = now + 30 * 60;

  const oHeader = { alg: 'HS256', typ: 'JWT' }

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

  const sHeader = JSON.stringify(oHeader)
  const sPayload = JSON.stringify(oPayload)
  const signature = KJUR.jws.JWS.sign('HS256', sHeader, sPayload, process.env.ZOOM_SDK_SECRET)

  res.json({
    signature: signature,
    sdkKey:process.env.ZOOM_SDK_KEY
  })
})

Tab 5 Content

    
      app.get('/oauthrefreshtoken', async (req, res) => {
        try {
            console.log("handle_oauth_refresh_token_data_request");
            
            var oauth_client_id="";
            var oauth_client_secret="";
            const code = req.query.code; // Get the token from the query string
            if (code && code.length>=1){
        
              
              // Encode the client ID and client secret
              const credentials = `${oauth_client_id}:${oauth_client_secret}`;
              const credentials_encoded = base64.encode(credentials);
              console.log(credentials);
              console.log(code);
    
    
    
              const url = 'https://zoom.us/oauth/token';
              const data = {
                refresh_token: code,
                grant_type: 'refresh_token'
              };
              
              const headers = {
                Authorization: `Basic ${Buffer.from(`${oauth_client_id}:${oauth_client_secret}`).toString('base64')}`,
                'Content-Type': 'application/x-www-form-urlencoded'
              };
              
              axios.post(url, new URLSearchParams(data).toString(), { headers })
                .then(response => {
          
        
          
                  console.log(response.data);
                  res.status(200).json(response.data);
                  // You can access the access_token in response.data.access_token
                })
                .catch(error => {
                  console.error(error);
                  res(error);
                  // Handle any errors here
                });
    
          }
          else{
            console.log("issue with ?code query string");
    
          }
        } catch (error) {
            console.error("Error:", error.message);
            res.status(500).send("Internal Server Error");
        }
    });
    
    

Tab 6 Content

    
// Function to make a REST API request using the bearer token
async function makeApiRequestWithToken(bearerToken,meetingNumber) {
  try {
    const apiUrl = `https://api.zoom.us/v2/meetings/${meetingNumber}/jointoken/local_recording`;
    
    // Define your API request parameters
    const apiRequestData = {
      method: 'GET', // Change to the HTTP method you need
      url: apiUrl, // Replace with your API endpoint URL
      headers: {
        'Authorization': `Bearer ${bearerToken}`,
        // Add other headers as needed
      },
    };

    // Send the API request with the bearer token
    const response = await axios(apiRequestData);
    const recordingToken = response.data.token;
    // Return the response data
    return recordingToken ;
  } catch (error) {
    console.error('Error making API request:', error.message);
    return error.message ; // Optionally rethrow the error
  }
}

Tab 7 Content

    

ZOOM_VIDEO_SDK_KEY="xxxxxxx"
ZOOM_VIDEO_SDK_SECRET="xxxxxxx"

#ZOOM_SDK_KEY="xxxxxxx"
#ZOOM_SDK_SECRET="xxxxxxx"


ZOOM_WEBHOOK_SECRET_TOKEN="xxxxxxx"


ZOOM_MSDKWEBHOOK_SECRET_TOKEN="xxxxxxx"
ZOOM_SDK_KEY="xxxxxxx"
ZOOM_SDK_SECRET="xxxxxxx"
ZOOM_CLIENT_ID_NEW="xxxxxxx"
ZOOM_CLIENT_SECRET_NEW="xxxxxxx"


ZOOM_VSDK_WEBHOOK_SECRET_TOKEN="xxxxxxx"

ZOOM_S2SOAUTH_WEBHOOK_SECRET_TOKEN="xxxxxxx"
ZOOM_S2S_CLIENT_ID="xxxxxxx"
ZOOM_S2S_CLIENT_SECRET="xxxxxxx"
ZOOM_S2S_ACCOUNTID="xxxxxxx"

ZOOM_OAUTH_ACCOUNTLEVEL_WEBHOOK_SECRET_TOKEN="xxxxxxx"
ZOOM_OAUTH_ACCOUNTLEVEL_CLIENT_ID="xxxxxxx"
ZOOM_OAUTH_ACCOUNTLEVEL_CLIENT_SECRET="xxxxxxx"


ZOOM_OAUTH_USERLEVEL_WEBHOOK_SECRET_TOKEN="xxxxxxx"
ZOOM_OAUTH_USERLEVEL_CLIENT_ID="xxxxxxx"
ZOOM_OAUTH_USERLEVEL_CLIENT_SECRET="xxxxxxx"





Tab 8 Content