Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Curl POST request to external Oath2 API

Tags:

php

curl

I'll try to sketch our situation:

  • We have a Wordpress website that needs to connect to an Oath2 API
  • I have little experience yet using API's and PHP
  • We are using a PHP-Oath2 library, which can be found here: https://github.com/adoy/PHP-OAuth2/tree/master/src/OAuth2

The method from the libary where we're stuck is executeRequest. This method can be found on line 404 (oh the irony) of https://github.com/adoy/PHP-OAuth2/blob/master/src/OAuth2/Client.php

Now, like I said, I've little experience in PHP so my way of debugging is just echo'ing the status of variables at given points in the script. Amateuristic as this may be, I could at least verify that the url and parameters are correct. I could print the complete URL (dummy parameter values ofc):

Mind the following parameters used: code, redirect_uri, grant_typen client_id and client_Secret.

https://oauth.smartschool.be/OAuth/index/token?code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc

When you execute this request, you'll get a JSON error message. Which is normal, as I cannot give you our client_id and client_secret:

{"error":"error_occured","error_description":"Client authentication failed."}

When I execute this manually in my browser (with the correct parameter values), I get the desired JSON result:

{"access_token":"fa4a6s4axsaxxsfacc56c4aca8acac4q6d5z4fsv","token_type":"Bearer","expires_in":3600,"refresh_token":"X5s1aq56xaq6bhz56aGY6SCb9845465czxqde56a"}

The problem is, when CURL builds and executes this as a POST request, I get an error JSON result:

{"error":"error_occured","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \u0022code\u0022 parameter."}

I can verify the status of the following CURL options (mind you that the code bypasses ssl verification, line 462 in the Client.php file):

  • CURLOPT_RETURNTRANSFER = true
  • CURLOPT_SSL_VERIFYPEER = false
  • CURLOPT_SSL_VERIFYHOST = false
  • CURLOPT_CUSTOMREQUEST = 'POST'
  • CURLOPT_POST = true
  • CURLOPT_POSTFIELDS = url encoded parameter string

example: code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2Fgrant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc

  • CURLOPT_URL = https://oauth.smartschool.be/OAuth/index/token
  • CURLOPT_HTTPHEADER => empty array

When executing this Curl handler like this:

$result = curl_exec($ch);

He does successfully reach out to the API and returns the result, but the JSON result shows a parameter error, claiming that the code is incorrect. But I know that it is correct, because when I execute the request manually via the browser, it works. If you go straight to https://oauth.smartschool.be/OAuth/index/token without parameters, you get that very same error.

This just makes me wonder whether curl passes any parameter at all.

Could you please tell me whether you spot an error somewhere in the provided ifno, perhaps in the curl options? Or could you guide me to a proper way to debug this curl execution (keeping in mind that I'm on Wordpress, if that matters at all).

Please let me know if this post lacks required information. Thank you in advance.

--EDIT:

The library code is triggered by the following lines of code (again, dummy client id and secret). This method can be found on line 211 of https://github.com/adoy/PHP-OAuth2/blob/master/src/OAuth2/Client.php

$client = new Client('5d6t5ev5a6d8', 'pada9c54a6sc');
$callBackUrl = 'https://mycallbackurl.com/my-page';
$myResponse = $client->getAccessToken('https://oauth.smartschool.be/OAuth/index/token', 'authorization_code', ['code'=> $_GET['code'], 'redirect_uri' => $callBackUrl]);

I've removed the code that puts the header option to an empty array, just to be sure. But when debugging with CURLINFO_HEADER_OUT, the result remains the same. It indeed defaults to Content-Type: application/x-www-form-urlencoded. Here's the complete curl_getinfo() array:

Array ( [url] => https://oauth.smartschool.be/OAuth/index/token [content_type] => application/json [http_code] => 200 [header_size] => 7414 [request_size] => 363 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.073514 [namelookup_time] => 3.9E-5 [connect_time] => 0.006093 [pretransfer_time] => 0.028232 [size_upload] => 216 [size_download] => 231 [speed_download] => 3142 [speed_upload] => 2938 [download_content_length] => -1 [upload_content_length] => 216 [starttransfer_time] => 0.073476 [redirect_time] => 0 [redirect_url] => [primary_ip] => xxx.xxx.xxx.xxx [certinfo] => Array ( ) [primary_port] => xxxxx [local_ip] => xxx.xxx.xxx.xxx [local_port] => xxxxx [request_header] => POST /OAuth/index/token HTTP/1.1 Host: oauth.smartschool.be Accept: */* Content-Length: 216 Content-Type: application/x-www-form-urlencoded )

The result, however, remains the same (still indication that no parameters were passed at all):

Array ( [result] => Array ( [error] => error_occured [error_description] => The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "code" parameter. ) [code] => 200 [content_type] => application/json )

Is there any way to print the parameters / post fields / body from this curl request, to verify that all information was sent?

-- EDIT2:

After using the httbin.org/post link which Tobias provided, I got the following result:

Array ( 
    [args] => Array 
        (
        ) 

    [data] => 
    [files] => Array 
        ( 
        ) 

    [form] => Array 
        ( 
            [client_id] => 5d6t5ev5a6d8
            [client_secret] => pada9c54a6sc
            [code] => fa4a6s4axsaxxsfacc56c4aca8acac4q6d5z4fsv
            [grant_type] => authorization_code 
            [redirect_uri] => https://mycallbackurl.com/my-page
        ) 

    [headers] => Array 
        ( 
            [Accept] => */* 
            [Connection] => close 
            [Content-Length] => 216 
            [Content-Type] => application/x-www-form-urlencoded 
            [Host] => httpbin.org 
        ) 

    [json] => 
    [origin] => 83.xxx.xx.xx
    [url] => https://httpbin.org/post 
) 

Comparing this to Tobias'example, I don't see any noteworthy differences. I assume this means that our POST request does at least contain all required data. We're still in the dark here then for what possible reason(s) the API does not accept the parameters. Should you come up with some other possible solutions, please don't hesitate to append them. Thanks for this dump link tho, this is really useful!

like image 808
J. Michiels Avatar asked Feb 03 '26 15:02

J. Michiels


1 Answers

There is a difference between your testing in browser and the actual code: In the browser, you pass the variables as GET parameters, while in your code you are sending a POST body.

To debug such issues I often find it easier to use CLI curl before going to PHP. When I send the request like this (mind the Content-Type header) I managed to get a positive result:

curl -X POST --data "code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc" "https://oauth.smartschool.be/OAuth/index/token" -H "Content-Type: application/x-www-form-urlencoded"
{"error":"error_occured","error_description":"Client authentication failed."}

I was able to reproduce your error when I forcefully send the request without this header. This is actually not that easy, because using --data automatically adds it:

curl -X POST --data "code=irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk&redirect_uri=https%3A%2F%2Fmycallbackurl.com%2Fmy-page%2F&grant_type=authorization_code&client_id=5d6t5ev5a6d8&client_secret=pada9c54a6sc" "https://oauth.smartschool.be/OAuth/index/token" -H "Content-Type: "
{"error":"error_occured","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \u0022grant_type\u0022 parameter."}

You need to make sure your code sends the request with the header: Content-Type: application/x-www-form-urlencoded.

I'd guess that PHP-curl would also implicitely add it when using POST(FIELDS) (analog like the CLI version does), and your issue may be that you "forcefully" set CURLOPT_HTTPHEADER to an empty array and thus remove it.

To debug the headers that are being sent you can use:

curl_setopt($ch, CURLINFO_HEADER_OUT, true);
// curl_exec
$information = curl_getinfo($ch);
print_r($information);

Edit:

What is actually even better to debug is to change your OAuth-URL where the POST goes to https://httpbin.org/post. This will just mirror everything that was sent to it, so then dump the response you get, it should look like:

Array
(
    [result] => Array
        (
            [args] => Array
                (
                )

            [data] =>
            [files] => Array
                (
                )

            [form] => Array
                (
                    [client_id] => 5d6t5ev5a6d8
                    [client_secret] => pada9c54a6sc
                    [code] => irsyB0VSmg4V5dVjHFgdl85iRvvu3gYpsuIE4cOk
                    [grant_type] => authorization_code
                    [redirect_uri] => https://mycallbackurl.com/my-page
                )

            [headers] => Array
                (
                    [Accept] => */*
                    [Connection] => close
                    [Content-Length] => 180
                    [Content-Type] => application/x-www-form-urlencoded
                    [Host] => httpbin.org
                )

            [json] =>
            [origin] => 217.***.***.***
            [url] => https://httpbin.org/post
        )

    [code] => 200
    [content_type] => application/json
)

And you can hopefully identify what is being sent (and not) from there, including the body data. Not even curls verbose mode shows that unfortunately.

like image 149
Tobias K. Avatar answered Feb 06 '26 04:02

Tobias K.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!