Invalid Grant Type for Oauth app using PHP

Following the documentation provided here

Step 1, I am acquiring an authorization code from authorize endpoint.
On step 2 I am hitting this endpoint: and passing the value from step 1 to the code field.

I am passing “grant_type” as “authorization_code”.

Here is the response being provided: {“reason”:“unsupported grant type”,“error”:“unsupported_grant_type”}

Why is it saying “unsupported grant type?” This is exactly what the docs instruct you to do.

Hi @alanj
Thanks for reaching out to us and welcome to our community!
Have you been able to identify your issue here? are you still having trouble getting your access_token via OAuth?

I have not resolved this and get the same error.

@elisa.zoom adding this to make sure you get tagged

Hey @alanj
could you please confirm if you are using credentials associated with an OAuth app?

@elisa.zoom yes, this is confirmed

Thanks @alanj
Here is a very helpful post on how to use Oauth with postman:

If you can follow along, you might be able to identify the issue

@elisa.zoom This is nothing like the zoom guide I have been following in the slightest. Why isn’t the flow I linked in the original post not working? The guide you linked does not even use the same endpoints and is entirely at odds with the documentation.

Hi @alanj ,

Edit: I’ve just edited the above guidance to include the up to date information for manual OAuth authorization. Please reference our Postman workspace which accurately conveys what’s shared in our docs:

1 Like

@gianni.zoom I am still getting the same error after switching to a user level app and following the postman steps - I can obtain an authorization code just fine, but when I send that value in the code to the token endpoint, I receive an error in JSON that says unsupported grant type. It is also unclear why the endpoint asks for a redirect_uri, when the endpoint should simply return the access token and not redirect the user. The server itself is making this call, not the customer.

Are you creating an OAuth application or a Server-to-Server OAuth application? OAuth applications usually use a grant_type value of authorization_code and a Server-to-Server OAuth application uses a grant_type value of account_credentials.

Make sure to format the request body as a query string to align with the Content-Type: application/x-www-form-urlencoded header you’re passing. I feel that the OAuth 2.0 for user authorized apps walkthrough is providing misleading examples of what your request should look like.

I have switched to an Oauth user level app. I am passing the correct headers and values (authorization_code). I still receive the error.

Can you provide a code snippet of how you’re producing the request to I’m particularly interested in the headers are being prepared and how the body is being generated. Our application is sending Content-Type: application/x-www-form-urlencoded; charset=utf-8 and using PHP’s http_build_query function to produce the query string which should yield a body like grant_type=authorization_code&code=&redirect_uri=.

The docs say multiple times NOT to pass the grant_type or redirect URI through the query string. (However, I tried it, and it gives the same result.)

I am using php’s curl library.

Firstly, function for generating post fields (omitting signature for redundancy)

return [
         "code" => $authCode,
         "grant_type" => "authorization_code",
         "redirect_uri" => Yii::$app->params["zoom"]["auth"]["redirect_url"],

Generating the headers:

      return [
         "Authorization: " . AuthUtil::getAuthorizationHeader(),
         "Content-Type: application/x-www-form-urlencoded", 

Lastly, the actual calling functions (functions here call the above), $p and $q variables are for debugging purpose

$curl = curl_init(Yii::$app->params["zoom"]["auth"]["access_token"]);
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $p = AuthUtil::getAccessTokenPost($authCode));
      curl_setopt($curl, CURLOPT_HTTPHEADER, $q = AuthUtil::getAccessTokenHeaders());
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($curl, CURLINFO_HEADER_OUT, true);

      $data = curl_exec($curl);
      $info = curl_getinfo($curl);

      if ($info["http_code"] != 200)

         return null;

      return json_decode($data);

just so you know, i am waiting too for a solution in this case :smiley:

Per the PHP documentation for curl_setopt’s CURLOPT_POSTFIELDS, I’m concerned that you are taking a contradictory position on Content-Type where passing a PHP array implies a Content-Type of multipart/form-data (which I don’t think Zoom officially accepts), while you are intending to use application/x-www-form-urlencoded (which Zoom is known to accept). Can you verify the actual headers that are being sent?

I can confirm the proper header is being sent, by debugging the $info variable:

Accept: */*
Authorization: Basic [[REDACTED]]
Content-Length: 453
Content-Type: application/x-www-form-urlencoded; boundary=------------------------39dea308112275e8

The inclusion of a boundary keyword suggests you are triggering residual behavior from multipart/form-data.

Per php’s curl documentation, if CURLOPT_POSTFILEDS is set to an array, then boundary is automatically set and the multipart/form-data is set as well. I will try passing in & delimited parameters and get back to you very shortly.

@MultiplayerSession that did it!

PHP does not permit the overriding of the header. I assumed that the boundary would be necessary after all.

@vasilca.matei.ovidiu if you are using php, pass in a string rather than an array to CURLOPT_POSTFIELDS.