Invalid access token and "reason": "unsupported grant type", "error": "unsupported_grant_type"

Before Creating a New Topic:

If you’re experiencing unexpected Video SDK behavior please search the forum with relevant keywords (e.x. error message) and follow the guidance outlined in those posts. Please also leverage the following support links:


Description
{“code”: 124, “message”: “Invalid access token.”} and {“reason”: “unsupported grant type”, “error”: “unsupported_grant_type”}

Browser Console Error
Got above message while trying your postman collection Postman

Which Web Meeting SDK version?
whatever the above collection uses

Meeting SDK Code Snippets
[The code snippets that are causing the error / issue so we can reproduce.]

app.post("/create-meeting2", async (req, res) => {
  console.log('abc');

  let oPayload = {
    
      method: "POST",
      body: {
        agenda: "This is Meeting",
        default_password: false,
        duration: 60,
        password: "123456",
        pre_schedule: false,
        recurrence: {
          end_date_time: "2024-04-18T19:35:00Z",
          end_times: 7,
          monthly_day: 1,
          monthly_week: 1,
          monthly_week_day: 1,
          repeat_interval: 1,
          type: 1,
          weekly_days: "1",
        },
        schedule_for: "vaibhav.ga@cisinlabs.com",
        settings: {
          additional_data_center_regions: ["TY"],
          allow_multiple_devices: true,
          alternative_hosts: "gws.gorank@gmail.com;",
          alternative_hosts_email_notification: true,
          approval_type: 2,
          audio: "telephony",
          audio_conference_info: "test",
          authentication_domains: "localhost",
          authentication_exception: [
            {
              email: "vaibhav.ga@cisinlabs.com",
              name: "Vaibhav Ga",
            },
          ],
          authentication_option: "signIn_" + process.env.ZOOM_MEETING_SDK_KEY,
          auto_recording: "cloud",
          breakout_room: {
            enable: true,
            rooms: [
              {
                name: "room1",
                participants: ["gws.gorank@gmail.com"],
              },
            ],
          },
          calendar_type: 1,
          close_registration: false,
          contact_email: "gorank.j@cisinlabs.com",
          contact_name: "Jill Chill",
          email_notification: true,
          encryption_type: "enhanced_encryption",
          focus_mode: true,
          global_dial_in_countries: ["US"],
          host_video: true,
          jbh_time: 0,
          join_before_host: false,
          language_interpretation: {
            enable: false,
          },
          sign_language_interpretation: {
            enable: false,
          },
          meeting_authentication: false,
          meeting_invitees: [
            {
              email: "gws.gorank@gmail.com",
            },
          ],
          mute_upon_entry: true,
          participant_video: false,
          private_meeting: false,
          registrants_confirmation_email: false,
          registrants_email_notification: false,
          registration_type: 1,
          show_share_button: true,
          use_pmi: true,
          waiting_room: false,
          watermark: false,
          host_save_video_order: true,
          alternative_host_update_polls: true,
          internal_meeting: false,
          continuous_meeting_chat: {
            enable: true,
            auto_add_invited_external_users: true,
          },
          participant_focused_meeting: false,
          push_change_to_calendar: false,
          resources: [
            {
              resource_type: "whiteboard",
              resource_id: "X4Hy02w3QUOdskKofgb9Jg",
              permission_level: "editor",
            },
          ],
          auto_start_meeting_summary: false,
          auto_start_ai_companion_questions: false,
        },
        start_time: "2024-04-18T19:35:55Z",
  
        timezone: "Asia/Kolkata",
        topic: "My Meeting",
  
        type: 1,
      },
      signature: req.body.signature,
      auth: {
        bearer: req.body.signature,
      },
      headers: {
        "User-Agent": "Zoom-api-Jwt-Request",
        "content-type": "application/json",
        Authorization: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZGtLZXkiOiJrc3BOd09TOVNLdThYaUx1cUlHc2N3Iiwicm9sZSI6MCwiaWF0IjoxNzEzNTI5OTQ1LCJleHAiOjE3MTM1MzcxNDUsImFwcEtleSI6ImtzcE53T1M5U0t1OFhpTHVxSUdzY3ciLCJ0b2tlbkV4cCI6MTcxMzUzNzE0NX0.WGWXONlF0GPHWmr_mYmdBj8kK0MxUXkCpTEs2CCON4k`
      },
      json: true, //Parse the JSON string in the response
    
  
  };

  const sPayload = JSON.stringify(oPayload);

  const data = await axios({
    url: "https://api.zoom.us/v2/users/me/meetings",
    method: 'POST',
    data: sPayload,
    headers: {
      Authorization: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZGtLZXkiOiJrc3BOd09TOVNLdThYaUx1cUlHc2N3Iiwicm9sZSI6MCwiaWF0IjoxNzEzNTI5OTQ1LCJleHAiOjE3MTM1MzcxNDUsImFwcEtleSI6ImtzcE53T1M5U0t1OFhpTHVxSUdzY3ciLCJ0b2tlbkV4cCI6MTcxMzUzNzE0NX0.WGWXONlF0GPHWmr_mYmdBj8kK0MxUXkCpTEs2CCON4k`
    },
  })
  .then(response => {
    return response;
  })
  .catch(error => {console.log('error', error)})

  res.json({
    data
  })
})

To Reproduce(If applicable)
Steps to reproduce the behavior:

  1. Go to ‘…’
  2. Click on ‘…’
  3. Scroll down to ‘…’
  4. See error

Screenshots
If applicable, add screenshots to help explain your problem.

Troubleshooting Routes
tried your postman collection and on node js tried many ways I also checked and enabled the permission in scopes

Device (please complete the following information):

  • Device: [hp Desktop]
  • OS: [Ubuntu 22.04]
  • Browser: [Chrome]
  • Browser Version [Version 124.0.6367.60 (Official Build) (64-bit)]

Additional context
Got signature using your React and node sample code but unable to create a meeting

@gorank.j are you using general app, s2s oauth app or any other specific app type?

Hello @chunsiong.zoom
Thanks for the reply
Its “general app 21”

and I want to use it with my local machine. I mean the redirect url I put on it is http://localhost:3000

Here’s the things which you need to fix @gorank.j

General App uses Oauth Flow.

  1. Use the OAuth flow to get the correct access token. The current access token (bearer token) which you are using is valid only for Meeting SDK Auth.
  2. You will need a publicly resolvable URL for the redirect URL. Localhost is not resolvable. You might want to look at something such as ngrok

Here’s a sample using nodejs, on how redirect URL uses the to get an access token
https://nodejs.asdc.cc/#redirect-url-for-oauth

Here’s a sample which uses the access token to call the REST API
https://nodejs.asdc.cc/#call-zoom-rest-api

Hello @chunsiong.zoom ,
Thanks you for the response!
I changed the localhost url to a public resolvable url: https://api.foreignchatweb.com/svconsultation/createZoommeeting

and tried to get access token but it keeps giving me data: { code: 124, message: ‘Invalid access token.’ }

Please note that I’m running a free zoom marketplace account and the frontend is on localhost. I uploaded the node code on the url above. I also tried ngrok but I was getting invalid domain url error so I had to change it to public resolvable url mentioned above.

Below were the request params I attached
topic:cis meeting
startTime:2024-05-05 18:00:00.000
duration:60

And the response I got
response: {
status: 401,
statusText: ‘Unauthorized’,
headers: Object [AxiosHeaders] { …

Could you please suggest what am’i missing in the request?

@gorank.j what language are you using ? javascript + nodejs?

Hello @chunsiong.zoom

  1. Yes! I’m working react with node express js and have already downloded the samples of both. but create meating api giving me invalid token.

  2. I’m trying to pass the signature I downloaded from back end point sample of node js and with the same signature (token) which I passed in header as Bearer: myToken. but it says invalid token.

  3. I can see my app status as draft. Do I have to publish it in marketplace in order to get the token?

Looking forward for your response
Thank you

@gorank.j

This is going to be a multi-part response

I’m doing something like this to handle the oauth’s redirect URL

  // 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
 
  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 => {


        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{
   
    
        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);
});

@gorank.j

To call the API, I’m using the access token (bearer token) from the previous reply.
The example below tries to get a meeting token, but you can change the URL, HTTP VERB and Payload for Creating Meeting

// 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
  }
}

@gorank.j

You do not need to publish your app for the token to work

Thank for the reply @chunsiong.zoom !

I used below code and getting 400 and 401 codes in response.

Please review the attached screen shot first screen I would like to show you the credentials I’m copying from. While the second screenshot denying me to put my dev server url in Domain allow list.

Please note that I’m using two different accounts to test and the token below corresponds to another account. I want to mention the script which I modified after your last response.

svc.createZoommeeting = async (req, res) =>{

// const apiKey = ‘t3ZSM76QeK702ekb9caA’;
// const apiSecret = ‘gNGI6YJk2pYuQQ5xlutw2YqglNdUzKLt’;

var clientid= ‘t3ZSM76QeK702ekb9caA’;
var clientsecret= ‘gNGI6YJk2pYuQQ5xlutw2YqglNdUzKLt’;
path = ‘’;
// handleRedirectURLDataRequest(“redirecturlformsdkoauth”,clientid,clientsecret, req, res);

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

console.log(‘aaaaaaaaa’);
if (codeFromQueryString && codeFromQueryString.length>=1){
console.log(‘bbbbbbbbb’);

//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
  redirect_uri: 'https://spnode4002.elb.cisinlive.com/'+path

};

//https://spnode4002.elb.cisinlive.com

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 => {


    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);
    res.status(500).json(error);
    // Handle any errors here
  });

}
//if there is no querystring entered
else{


    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' });
    }
  }

}
clientId