In-client OAuth not accepting post requests

Attempting to follow the In-client Oauth flow, and finding I am unable to make a POST request to the auth/token endpoint.

Specifically, when onAuthorized is called, I initiate the following POST request as per the documentation:

zoomSdk.onAuthorized(async (event) => {
      console.log("onAuthorized: ",event);
        function (data, status){

In the console, this results in:

[Error] Origin is not allowed by Access-Control-Allow-Origin.
[Error] XMLHttpRequest cannot load due to access control checks.
[Error] Failed to load resource: Origin is not allowed by Access-Control-Allow-Origin. (token, line 0)

In-client OAuth has been turned on for the app, the domain has been added to the Apps “OAuth allow list,” and the domain has been added to the “Domain allow list.”

What am I missing?

Have you properly set your OWASP headers in the app?

Hi @ash.provost, thanks for the quick response.

The headers set on our server don’t seem to make any difference (eg tried setting "Access-Control-Allow-Origin: *").

As far as I understand, the issue is that the headers on the Zoom API endpoint are not allowing requests from the ngrok domain, despite it being added to the OAuth and Domain allow lists within the app.

Can you confirm the API url is correct? Are there any headers it is expecting that aren’t in the documentation? Anything else I could be missing?

Hi @vandalayindustries I think Ash means this …
Zoom Developer Docs - OWASP

I haven’t tried what you are doing yet but I need to here in the near future. I’ve been looking at the advanced sample and trying to match what it does. It does have these headers.
zoom/zoomapps-advancedsample-react: (

(I’m also seeing CORS issues when I call an api locally from my app … it works ok if I publish my app somewhere though. I’m looking at verifying these headers.)

Hey @andy1 thanks for the pointer.

I tried using the OWASP headers set in the advancedsample app you pointed out. Specifically those found here:

    res.setHeader('Strict-Transport-Security', 'max-age=31536000')
    res.setHeader('X-Content-Type-Options', 'nosniff')
    // This CSP is an example, it might not work for your webpage(s)
    // You can generate correct CSP for your webpage here
    const publicUrl = process.env.PUBLIC_URL
    const { host } = new URL(publicUrl)
      `default-src *; style-src 'self' 'unsafe-inline'; script-src * 'self' '' 'unsafe-inline'; connect-src * 'self' wss://${host}/sockjs-node; img-src 'self' data:; base-uri 'self'; form-action 'self';`
    res.setHeader('Referrer-Policy', 'same-origin')
    res.setHeader('X-Frame-Option', 'same-origin')

Sadly I am still getting the same error. I thought the issue might be with ngrok not passing the headers through, but starting ngrok with the -host-header=rewrite did not resolve the issue either.

It would be helpful if the fail response was a little more specific as to what specific header or permission is missing. Any other idea on what I could be missing here (+ @ash.provost )?

@vandalayindustries Can you send a screenshot of the headers your page is serving?

Hi @MaxM ,

These are the headers on the Development “App home url”:

The POST request itself is as follows (no specific headers set as shown in the documentation)

Appreciate any insights!

@vandalayindustries Zoom’s authorization server does not allow cross origin requests, so the browser is blocking the response. You will need to make this request server-side.

Also noting the token endpoint is

We will update the docs to clarify how to use this flow.

Thanks @daniel.fried , that would explain why we are running into a wall here.

I tried sending the request from the server side the same way as in the standard (not in-client) OAuth, but am getting a “Invalid authorization code” response. Specifically, posting to[CODE]&redirect_uri=[REDIRECT_URI]

where the CODE and REDIRECT_URI parameters are provided by the onAuthorized event data. Is there some other grant_type parameter that needs to be set here or something?

Are you providing the basic auth header?

Hi @daniel.fried , yes I am including the basic auth header. As far as I can tell the header is set correctly. I.e. if I omit or send the incorrect header then it will give me a different error Invalid client_id or client_secret.

Wild guess … does the code need to use encodeURIComponent()?

Good thought…just tried but sadly get the same response. Seems the code is always alphanumeric so encodeURIComponent doesn’t have any effect.

@daniel.fried or other Zoom folks, any other ideas why the authorization code is being rejected?

Here’s an example of a code being received onAuthorized:

And then immediately rejected. The code and redirect_uri are identical to what is received above:

have you tried adding mode:“no-cors” in request options

Interesting idea. I just gave mode: 'no-cors' a try but still get the same response. Seems like the request is now making it fine to the API endpoint…the issue seems to be that it is not accepting the code provided by the onAuthorized function.

So error code 400 Bad Request is shown, i.e server is now denying the request. I have also created a custom server and am facing the same issue, the request makes fine to the server, but the server is rejecting it. I think this has something to do with the proxy.
@daniel.fried @MaxM any solutions on this?

@njain4_be19 Just to confirm, are you able to make that same request outside of the client without an issue? What steps can I take to reproduce this issue on my end?

yes I used postman to check my api it worked fine.
So to reproduce make a fetch request to any other custom backend that you have hosted and then it will give 400 bad request on custom the backend side which means request is getting their but is rejected. I was able to find a work around by first send trigger data from inclient react app to app backend and then to my backend . I am using the advanced react sample on github to develop further

Sorry for the delay here. So far, I haven’t been able to reproduce this on my end. I’m glad you have a path forward but if there is a bug I want to make sure it’s addressed.

You mentioned that your custom backend returns the 400 error. Have you had a chance to capture logs from the backend?