Tuesday 19 January 2021

Connect to Zoom API with Apps Script and OAuth

The following blog post is about connecting to the Zoom API by creating a Zoom OAuth App and then using a Web App designed in Google Apps Script. Our aim here is to return an Access Token which could then subsequently be used to access Zoom account data (eg your profile, meetings, etc).

Here are some useful links:

 

Process overview

There are a set of steps that we need to complete in order to achieve successful authentication (connection with our Zoom account via the Zoom API):

  1. Have a user visit a dedicated URL (which comes from our Web App).
  2. This URL is attached to our Zoom OAuth App and upon a user visiting, it returns an Authorisation Code.
  3. Our Web App then uses this Authorisation Code along with the Client ID and Client Secret (generated when we created the Zoom OAuth App) to make another request that finally returns an Access Token, valid for 1 hour.
  4. Further blog posts will explore how we then get Zoom account data, create meetings, etc with the Access Token.


Creating the Web App

You will need to follow these instructions to deploy a script as a Web App, from which you will get a URL that will be connected to your Zoom OAuth App. Whether you do this before or after implementing the below code is up to you.

We begin with the Function that is called when a user visits the given webpage - 'doGet(e)' - which captures the HTTP request. The 'e' contains an event parameter (the Authorisation Code in this instance) that we want to extract from the URL:

// get authorisation code from returned Url
var authCode = JSON.stringify(e.parameter.code);
// remove quotes around the code
var authCodeClean = authCode.replace(/['"]+/g, '')

There is also a regular expression used above to remove the set of double quotes from the returned value (the Authorisation Code) as these double quotes will interfere with the next step if they are left in place.

Next we're ready to call the getToken Function, into which we pass the Authorisation Code. First we define the necessary authentication required by the Zoom OAuth App:

// set authentication and get OAuthKeys
var clientID = "ENTER YOUR APP ID HERE";
var clientSecret = "ENTER YOUR APP SECRET HERE";
var encodedKeys = Utilities.base64Encode(clientID + ":" + clientSecret);


//Set the HTTP headers
var options = {
  'method': "post",
  'headers': {"Authorization": "Basic " + encodedKeys},
};

Now we can make the call to the Access Token URL as specified by the Zoom documentation:

// Web App URL linked to Zoom OAuth App
var returnUrl = "ENTER YOUR WEB APP URL HERE";


// make Zoom OAuth call
var response = UrlFetchApp.fetch("https://zoom.us/oauth/token?grant_type=authorization_code&code=" + authCodeClean + "&redirect_uri=" + returnUrl, options);

Lots of information is returned so the final step we perform is to extract the Access Token specifically:

// run Function to extract Access Token
var resultText = response.getContentText();
var resultObj = JSON.parse(resultText);
var accessToken = resultObj['access_token'];

It is from this point here that we can now make use of the rest of the Zoom API as we have authenticated our account for access. I will look to cover this in the next couple of blog posts.

 

Creating the Zoom OAuth App

In conjunction with the above we need to have a Zoom OAuth App setup and linked to the Web App. Use these instructions to create the Zoom OAuth App. A couple of points about the one I created:

  • It is a user-managed app, meaning it is installed and authorised by users individually.
  • The 'Redirect URL for OAuth' is the URL for your Web App. I replaced the 'exec' at the end of mine for 'usercallback' instead
  • Turned off 'Event Subscriptions'.
  • Scopes: meeting:read, meeting:write, user:read, user_profile

Once you are happy and have completed the necessary information you can try visiting your Web App URL, authorise your account with Zoom and then capture your Access Token.


File Download

Download the Zoom API with Apps Script and OAuth here. Please use 'File' > 'Make a copy' for your own version. This is a Google Sheet with the Apps Script bound to it. You will need to deploy it as a Web App and create your own Zoom OAuth App.


17 comments:

  1. I have been working on the exactly same thing today. And your post just showed up now. Thank you! I will try and get back :)

    ReplyDelete
    Replies
    1. Good luck John!

      Kind regards
      Phil

      Delete
    2. I started with your example and it helped me a lot understand how OAuth2 works.
      Later I found the OAuth2 GAS library and used it for my project. https://github.com/googleworkspace/apps-script-oauth2
      I was confused in the beginning if I need to publish as webapp and use doGet method when I use their library. Using the library I just need to set endpoint URL to "https://script.google.com/macros/d/{SCRIPT ID}/usercallback". It works without "Publishing as Web App" which was time saver.

      Delete
    3. Hi John

      That's really interesting - I'm taking a look now!
      Do you happen to have an example of what you've created? Did you need the 'doGet' - I seem to be getting a Url error in my attempts :(

      Kind regards
      Phil

      Delete
    4. Phil, I used their sample. https://github.com/googleworkspace/apps-script-oauth2/blob/master/samples/Zoom.gs

      Delete
    5. Hi John

      Thank you very much for sharing this! Not sure why I never found it in my research! The only thing for me is that I'm not sure I can avoid a Web App as my pet-project is a solution that allows staff/students to bulk create Google Calendar events from a Google Sheet, with optional Meet or Zoom video conferencing.

      Using a Web App as a 'middle-man' means only I need to go through the process of creating a Zoom Marketplace App, of which the Client Secret can be hidden in the Web App and not seen by end users.

      This Library method you've shared is certainly better suited for individuals doing their own thing with their own credentials.

      Kind regards
      Phil

      Delete
  2. i keep getting an error

    Exception: Request failed for https://zoom.us returned code 401. Truncated server response: {"reason":"Invalid client_id or client_secret","error":"invalid_client"} (use muteHttpExceptions option to examine full response). (line 60, file "1) doGet")

    ReplyDelete
    Replies
    1. Hi

      This is difficult to diagnose are there are a lot of moving parts here I'm afraid. This sounds like your Zoom App and Web App may be the problem but I can't really assist any further I'm afraid.

      Kind regards
      Phil

      Delete
    2. Hello, Mr. Bainbridge.

      I get the same error that the user above, could it be something to do with changes in the zoom marketplace? I mnetion this because the guide for OAuth in zoom marketplace uses a different sintax. e.g.
      You used:
      var response = UrlFetchApp.fetch("https://zoom.us/oauth/token?grant_type=authorization_code&code=" + authCodeClean + "&redirect_uri=" + returnUrl, options);

      But in the mentioned guide, they use this instead:
      https://zoom.us/oauth/authorize?response_type=code&client_id=7lstjK9NTyett_oeXtFiEQ&redirect_uri=https://yourapp.example.com

      Kind regards
      Rodrigo

      Delete
    3. NVM my last reply, my error was that when i deply the web app, the url for it do changes, so i get that message, now i have other error that goes like:
      403 {"reason":"Invalid request : Redirect URI mismatch.","error":"invalid_request"}

      Delete
    4. Hi Rodrigo

      Thanks for providing the follow-up. You should be able to make changes to your Web App and deploy a new version without the whole Url changing (https://developers.google.com/apps-script/concepts/deployments#versioned_deployments).

      If it has changed remember you will need to update the Redirect Url in the Zoom Marketplace App.

      Kind regards
      Phil

      Delete
    5. Hello again, Mr. Bainbridge.

      Just to complete the follow-up I must say that i kept receiving the error {"reason":"Invalid request : Redirect URI mismatch.","error":"invalid_request"}, after a deep dive into the Zoom Developer Forum, the solution given there was to check that the "Redirect URL for OAuth" in the Zoom app, and the "&redirect_uri=" were the same. But after trying the same on and on checking that this were true for my case, it turns out i cant deploy the web app and copy the url, then paste it on the web app code and save, because this gets me to the error mentioned above, so i tried using the 'Deploy Test' on appscript which gave me a url with "/dev" at the end.
      I copy this url and pasted it on the code for the web app and re-deployed (test) and still get the same url, then i proceeded to paste this url over the zoom app, then installed and finally get to the 'Success! You can close this tab.' message.

      I hope i can get along with this method meanwhile trying to correct things to not get the error message using the "normal" deploy option.

      Thanks again for this article.

      Rodrigo.

      Delete
    6. Hi Rodrigo

      Thank you for taking the time to explain your troubleshooting, hopefully it may support anybody else who gets stuck.

      Kind regards
      Phil

      Delete
  3. Phil, this post helped me great deal. Thanks for this post.

    ReplyDelete
  4. Thanks for Phil's post and Rodrigo's sharing.
    I use the 'Deploy Test' and get to the 'Success!'.

    Although I tried to use the same url by choose "Manage Deployments > Deploy" but still get the same error message {"reason":"Invalid request : Redirect URI mismatch.","error":"invalid_grant"} by using the "normal" deploy option.

    Have you or anyone found the right way?

    ▼How to not change published url of script implementation after every change in code
    https://stackoverflow.com/questions/72715589/how-to-not-change-published-url-of-script-implementation-after-every-change-in-c

    ReplyDelete
    Replies
    1. Hi

      You're welcome.

      Have you updated your Zoom OAuth App with the correct Web App URL for your live version?

      Delete