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 = 'redacted';

  var clientid= 't3ZSM76QeK702ekb9caA';
  var clientsecret= 'redacted';
  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

@gorank.j the domain should be without https://

it should spnode4002.elb.cisinlive.com

You should be looking at Basic Information instead of Surface

You client ID and client Secret should be the 2 values on the top left

Hello @chunsiong.zoom
I think I got your point. Please let me check Thank you!

Hello @chunsiong.zoom

I want to create a website in which with the help of zoom features, the end users will be able to create a new meeting or join a meeting.

I did following:

  1. added my card to manage roles

  2. created “general app 21” under marketplace and added my domain url.

  3. I migrated a user to zoom to authenticate from Error - Zoom

  4. Now once the user click on the button he will be redirected to the zoom login page and after auth it redirected back the user to the mentioned redirect uri which I managed in the backend from node express.

  5. I got a code=xxxx as get parameter after which the user redirected back to my app.

  6. Now using the following code and the one you sent above, I tried to create a meeting for that user so that it can send it to the other users to connect with them. But I am getting response data: { code: 124, message: ‘Invalid access token.’ }

https://api.zoom.us/v2/users/me/meetings

app.post(‘/create-meeting’, async (req, res) => {
try {
const response = await axios.post(‘https://api.zoom.us/v2/users/me/meetings’, {
topic: ‘Test Meeting’, // Change this to your desired meeting topic
type: 1, // Scheduled meeting
settings: {
join_before_host: true
}
}, {
headers: {
‘Authorization’: Bearer ${generateZoomJWT()}
}
});

res.json(response.data);

} catch (error) {
console.error(‘Error creating meeting:’, error);
res.status(500).json({ error: ‘Failed to create meeting’ });
}
});

hello @chunsiong.zoom

After some research I found that I’m unable to follow these steps but I can’t see the option to create JWT app mentioned below. Could you please guide me:

Steps to Create and Configure a JWT App

  1. Create a JWT App in Zoom:
  • Go to the Zoom App Marketplace.
  • Click on “Develop” and then “Build App”.
  • Select “JWT” and follow the prompts to create your JWT app.
  1. Get the API Key and API Secret:
  • After creating the JWT app, you will be provided with an API Key and an API Secret. These are different from the Client ID and Client Secret used for OAuth2.0.

@gorank.j where are you reading this guide from? We might need the address to take it down / update it

JWT app type has bee deprecated for many months now, and what you might be following is no longer relevant

Hello @chunsiong.zoom ,
I got this from chatGpt and I know its not updated. But I am looking for any guideline or steps by step guide to integrate your auth 2 and then my user could initiate a meeting with a link. Here I am taking the token from backend node express and trying to manage it from the frontend which is in react.

ngrok serves the node link of the backend which I provided as redirect url which I whitelisted to the zoom marketplace account. I followed the guide but what I think I am missing is the step to handle correctly the redirection from zoom after auth as it is on my backend and my client is going to use the frontend. Could you please help me with steps by step guide on below points please?

  1. Auth 2.0
  2. and then using its token from node express backend I could initiate a meeting for that user on the React frontend

@gorank.j

you will need to do all of these on the backend. you cannot call them from the front end.

  1. OAuth 2.0 (Get code)
  2. Use code to get Access Token
  3. Use Access Token to call Create Meeting (You will get the Meeting ID and Password_

For the front end, if you want to join the meeting, you will need a Meeting SDK or General App (Meeting SDK Enabled).

Download the Meeting SDK for Web, and integrate it into your website.
Use the Meeting ID and Password from the above Step 3 to join the meeting.

Hello @chunsiong.zoom
I completed the process but it is like

  1. I’m redirecting user from frontend to backend which opens a pop up or redirect to zoom OAuth.
  2. Then user have to login there
  3. after Success he is redirected back to my site and now he is able to create meeting

Question: Is there a way that I dont have to redirect to zoom and do it directly with api to get token?

@gorank.j you can try using server to server oauth app. The process flow however is a bit different