BUG downloading cloud recordings with access token set results in an invalid response

In the meantime, I can think of two possible dirty workarounds:

  1. If we know the meeting/recording password, is it possible to add that as a URL param? e.g., http://zoomdownloadurl?password=fq4oijf!!ef
  2. If not, we can use the API to remove the password, download the video, and then re-add the password. Only problem with this is that we need to also request the scope “recordings:write”. You’re shit out of luck if you’ve already got users and they don’t have this scope.

Here’s JS example code for workaround number 2. I’ve tested it and it works. But you need the scope “recording:write”

const axios = require('axios');

(async () => {
  try {
    const meetingUuid = YOUR_MEETING_ID;
    const meetingUuidEncoded = encodeURIComponent(encodeURIComponent(meetingUuid));
    const jwt = OAUTH_JWT;

    // Get meeting password
    const meetingPassword = (await axios.get(`https://api.zoom.us/v2/meetings/${meetingUuidEncoded}/recordings/settings?access_token=${jwt}`)).data.password;

    // Remove meeting password
    await axios.patch(`https://api.zoom.us/v2/meetings/${meetingUuidEncoded}/recordings/settings?access_token=${jwt}`, { password: '' });

    // Download recording
    const recording = (await axios.get(DOWNLOAD_URL)).data;

    // Add meeting password back
    await axios.patch(`https://api.zoom.us/v2/meetings/${meetingUuidEncoded}/recordings/settings?access_token=${jwt}`, { password: meetingPassword });
  }
  catch (err) {
    console.error(err);
  }
})();

So gross haha. Note that there may be other restrictions on your user’s meeting recordings, so you might have to patch more than just the password (e.g., expiry), but I’ve kept the example short for demonstration purposes.

Hey @james2,

In the release this weekend, you will now be able to download password protected cloud recordings with OAuth apps. :slight_smile:

Thanks,
Tommy

3 Likes

That’s a big turnaround! Thanks for listening - glad Zoom upped the priority of this bug.

I’m interested to see that you still need the “recording.write” scope in order to download a password protected recording. That’s a bit odd, isn’t it, to need to “write” to the recording just to download? Funnily enough, it’s actually the same scope needed for my workaround above - is the new zoom update doing a similar thing under the hood?

I finally submitted our Zoom Marketplace Oauth app for my startup Videohop just yesterday, and had to include the “recording.write” scope for the workaround. Interesting to see that I will still need it even after the bug is fixed.

Thanks again for the quick communication, Tommy

1 Like

Really glad to see you are shipping this soon. One question:

Do we need all three of those scopes to be able to download or a least one of them?

Hey @zoom-test, @james2,

You just need one of those listed scopes. :slight_smile:

CC @Michael_Purnell can you update the docs to say one of these scopes.

Apologies again for the delays for this feature, but I am glad we were able to fit it in during our 90 day plan.

Thanks,
Tommy

Has this been included in the documentation yet? Looking for an example.

I’m getting a Forbidden error when authenticating using the Bearer authentication header.

Hey @JoshSTL,

Can you try adding it just as a query param:

download_url?access_token=OAUTH_ACCESS_TOKEN_HERE

Thanks,
Tommy

@tommy

Thanks for the reply!

I tried this method using curl, wget and just putting the url directly into a browser address bar. All fail with various messages returned:

wget:

HTTP request sent, awaiting response… 401

Username/Password Authentication Failed.

curl:

{“status”:false,“errorCode”:401,“errorMessage”:“Forbidden”}

I tried also including http authentication and a bearer token header, neither worked. The token is not expired as I can use it for other calls.

I am able to download the recording using the base URL in a browser session where the user has already authenticated using the web login on another page. But I’d like to be able to initiate the download from bash.