I need to connect to a REST API of a customer. The first step is to get an OAuth 2.0 access token. I got the following information from the customer:
- Login (I assume it’s the
client_id
) - Password (I assume it’s the
client_secret
) - The flow is
password
- The regular API URL
- The Token API URL
I found code at http://tutorialspage.com/simple-oauth2-example-using-php-curl/ and changed it, just for testing, to this:
private function getToken() { $curl = curl_init(); $params = array( CURLOPT_URL => self::API_TOKEN_URL, CURLOPT_RETURNTRANSFER => true, CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_POST => 1, CURLOPT_NOBODY => false, CURLOPT_HTTPHEADER => array( "cache-control: no-cache", "content-type: application/x-www-form-urlencoded", "accept: *", "accept-encoding: gzip, deflate", ), CURLOPT_POSTFIELDS => array( 'username' => urlencode('example@swagger.foo'), 'password' => urlencode('123 and 4'), 'grant_type' => 'password' ) ); curl_setopt_array($curl, $params); // test //curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); //curl_setopt($curl, CURLOPT_USERPWD, 'example@swagger.foo'.':'.'123 and 4'); $response = curl_exec($curl); $err = curl_error($curl); curl_close($curl); if ($err) { echo "cURL Error #01: " . $err; } else { $response = json_decode($response, true); if(array_key_exists("access_token", $response)) return $response; if(array_key_exists("error", $response)) echo $response["error_description"]; echo "cURL Error #02: Something went wrong! Please contact admin."; } }
I would expect to get a JSON response containing valid OAuth 2.0 access_token
, but instead I get an error:
{"error":"unsupported_grant_type"}
How to change the code to make it work?
Edit: It works over the shell-curl on my mac:
curl -i -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=password&username=example@swagger.foo&password=123 and 4' https://the-token-api-url.foo
Verbose Informations Curl (MacShell):
* Trying <IP HOST> * TCP_NODELAY set * Connected to <DNS HOST> (<IP HOST>) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /opt/local/share/curl/curl-ca-bundle.crt CApath: none * TLSv1.2 (OUT), TLS header, Certificate Status (22): * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Client hello (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Client hello (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / <something> * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=<CN> * start date: <date> * expire date: <date> * subjectAltName: host "<DNS HOST>" matched cert's "<DNS HOST>" * issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3 * SSL certificate verify ok. > POST /<URI PART>/token HTTP/1.1 > Host: <DNS HOST> > User-Agent: curl/7.58.0 > Accept: */* > Content-Type: application/x-www-form-urlencoded > Content-Length: 73 > * upload completely sent off: 73 out of 73 bytes < HTTP/1.1 200 OK HTTP/1.1 200 OK < Cache-Control: no-cache Cache-Control: no-cache < Pragma: no-cache Pragma: no-cache < Content-Type: application/json;charset=UTF-8 Content-Type: application/json;charset=UTF-8 < Expires: -1 Expires: -1 < Server: Microsoft-IIS/8.5 Server: Microsoft-IIS/8.5 < X-Powered-By: ASP.NET X-Powered-By: ASP.NET < Date: Tue, 05 Feb 2019 17:26:21 GMT Date: Tue, 05 Feb 2019 17:26:21 GMT < Content-Length: 671 Content-Length: 671
Verbose Informstions cURL PHP:
* Hostname in DNS cache was stale, zapped * Trying <IP> * TCP_NODELAY set * Connected to <DNS> (<IP>) port 443 (#0) * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /opt/local/share/curl/curl-ca-bundle.crt CApath: none * SSL connection using TLSv1.2 / <something> * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=<DNS> * start date: <date> * expire date: <date> * subjectAltName: host "<dns>" matched cert's "<dns>" * issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3 * SSL certificate verify ok. > POST /<uri part>/token HTTP/1.1 Host: <dns> cache-control: no-cache accept: * accept-encoding: gzip, deflate Content-Length: 384 Content-Type: application/x-www-form-urlencoded; boundary=------------------------<a hash> < HTTP/1.1 400 Bad Request < Cache-Control: no-cache < Pragma: no-cache < Content-Type: application/json;charset=UTF-8 < Expires: -1 < Server: Microsoft-IIS/8.5 < X-Powered-By: ASP.NET < Date: Tue, 05 Feb 2019 17:25:39 GMT < Content-Length: 34 * HTTP error before end of send, stop sending < * Closing connection 0
I didn’t find the problem.
Advertisement
Answer
OK, thanks to Helen it works now.
private function getToken(){ $curl = curl_init(); $params = [ CURLOPT_URL => self::API_TOKEN_URL, CURLOPT_RETURNTRANSFER => true, CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_POST => 1, CURLOPT_NOBODY => false, CURLOPT_HTTPHEADER => array( "cache-control: no-cache", "content-type: application/x-www-form-urlencoded", "accept: */*", "accept-encoding: gzip, deflate", ), CURLOPT_POSTFIELDS => "grant_type=password&username=username@example.foo&password=123and4" ]; curl_setopt_array($curl, $params); $response = curl_exec($curl); curl_close($curl); }
The Problem was solved as I entered the Post Data as String:
CURLOPT_POSTFIELDS => "grant_type=password&username=username@example.foo&password=123and4"
Instead of a array:
CURLOPT_POSTFIELDS => array( 'username' => urlencode('username@example.foo'), 'password' => urlencode('123and4'), 'grant_type' => 'password' )
Thanks <3!