Refreshed (new) Access Token throws 124:Invalid Access Token. Original AT works fine

Hi there!

Building an Oauth App.

User goes through OAUTH:
/oauth/authorize?response_type=code&client_id={Client ID}&redirect_uri={Redirect Uri}

Access Token and Refresh Token requested and received from Zoom:

Access Token works perfectly for any API request within specified allowed scope: |{ID} | etc

Refreshing an access token returns new Access Token and new Refresh Token:
/oauth/token?grant_type=refresh_token&refresh_token={Refresh Token}
New tokens are valid JWT tokens and can be decoded.

Using a newly refreshed Access Token on any endpoint throws 124:Invalid. This can be repeated over and over - i.e. refreshing a token with a new Refresh Token returns new tokens, and new Access Token throws 124:Invalid.

The only way to get a working valid Access Token is to send a user through initial OAUTH flow:
/oauth/authorize?response_type=code&client_id={Client ID}&redirect_uri={Redirect Uri}

I’m not sure if this is related to:

  • app is not yet live, but we got approval for external testing and have a publishable URL
  • we’re using production credentials (which seem to work perfectly for initial AT)
  • we’re refreshing Access Token before it expires - waited for AT to expire, new AT is invalid.

Hey @WMaster, thanks for posting and using Zoom!

Can you share the endpoints that are failing and the exact error message?

To confirm, you are able to refresh the tokens, but not use the access tokens?


Hi Tommy:

Thank you for replying!

I was able to solve this.

  1. I switched to dev credentials, thinking that maybe it had to do with production restrictions since we’re not live yet, but same issue occurred - can refresh endlessly, but requests fail with invalid AT. That meant it was definitely something on our end.

  2. I used CURL to refresh, then saved to DB so the code would pick it up - that worked - all requests were going through just fine.

That meant there was something in how token data was received/processed/stored on token refresh request.

This is being tested on node.js and we use built-in https module for requests. The code is dumb/simple:

let body=[];
response.on('data', chunk => {

response.on('end', () => {

If you can see it - the problem is body.join() - it uses a “,” by default, and sticks it between decoded chunks. So a response string “…NkLTBkYjUtNDE5Z…” turns into “…NkLTBkLTBk,YjUtNDE5Z…”.

While we could still decode the token with a “,” in payload since base64 doesn’t care about commas, obviously when we tried to request with the token, the payload+signature would not match on your end and you would reject it.

Simple switch to the following makes it all work:

response.on('end', () => {
  body = Buffer.concat(body).toString();
  // or body.join("");

And the reason the first access token worked is because OAUTH flow is handled by different code which processed the response correctly without adding “commas”…

1 Like

Ah gotcha @WMaster! Happy to hear you solved the issue! :slight_smile:

Thanks for explaining your solution too!

Let me know if you have additional questions!