environment:
- Ubuntu 18.04.5 LTS
- PHP 7.2.24-0ubuntu0.18.04.7
- curl 7.58.0
general behavior: I am using php cUrl to connect with a json rest api. Among others, the api spec shows a procedure to login.
on success, the api returns http level 200 and a success json string of something like
{
"token":"ey...RU",
"expiration":"2021-07-07T00:39:45"
}
On failure (bogus password, etc) it returns http level 401 and a json string of something like
{
"type": "https://tools.ietf.org/html/rfc7235#section-3.1",
"title": "Unauthorized",
"status": 401,
"traceId": "00-009af152168b684da1a6a543d11a3357-63fd91f4be1fc443-00"
}
i basically cloned the solution here How to curl via php, but without changes it returned 411 and no body. i experimented with different accept headers, without success. i also experimented with a content-length header to no avail. i finally settled on those in working bash curl method.
the jist: the json string is expected in both the success case and the failure case. in actuality, this is true for command-line land, but only true in the case of php curl with correct credentials.
there are several other msgs in the api which return various http level failure codes and, with bash curl, the json string is returned - php curl does not.
actual results: using either method with correct credentials, the success json string (giving token and expiration, shown above) is received.
if the credentials are not correct, bash curl returns the failure json string:
> curl -X POST "https://<api endpoint url>/api/Authenticate/login" \
-H "accept: text/plain" -H "Content-Type: application/json-patch+json" \
-d "{\"username\":\"valid_username\",\"password\":\"bogus_password\"}"
{"type":"https://tools.ietf.org/html/rfc7235#section-3.1",
"title":"Unauthorized",
"status":401,
"traceId":"00-a4edb6cfca5918499f1bfaa073206118-da71a7d85e582448-00"}
attempting to login with bogus credentials using php curl, it does not:
$curl = curl_init();
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_URL, '<the real json endpoint uri>);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_VERBOSE, true);
# curl_setopt($curl, CURLOPT_STDERR, $out);
$hdrs = ["accept: text/plain",
"Content-Type: application/json-patch+json"
];
curl_setopt($curl, CURLOPT_HTTPHEADER, $hdrs);
$params = ['username' => 'valid_username',
'password' => 'bogus password'
];
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
// json_encode sanitization omitted here for clarity
$output = curl_exec($curl);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if("200" != $responseCode)
$responseCode .= " - " . curl_error($curl);
$info = curl_getinfo($curl);
curl_close($curl);
print("==========\n\n");
printf("output: %s \n", var_export($output, true));
printf("responseCode: %s \n", $responseCode);
printf("info: %s \n", print_r($info, true));
print("==========\n\n");
the output: NOTE no failure json body.
* Trying 2xx.xxx.xx.xx...
* TCP_NODELAY set
* Connected to <the real json endpoint uri> (2xx.xxx.xx.xx) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=*.<the real json endpoint uri>
* start date: Jun 22 15:31:01 2021 GMT
* expire date: Sep 20 15:31:00 2021 GMT
* subjectAltName: host "<the real json endpoint uri>" matched cert's "<the real json endpoint uri>"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
> POST /api/Authenticate/login HTTP/1.1
Host: <the real json endpoint uri>
accept: text/plain
Content-Type: application/json-patch+json
Content-Length: 73
* upload completely sent off: 73 out of 73 bytes
* The requested URL returned error: 401 Unauthorized
* stopped the pause stream!
* Closing connection 0
==========
output: false
responseCode: 401 - The requested URL returned error: 401 Unauthorized
info: Array
(
[url] => https://<the real json endpoint uri>
[content_type] =>
[http_code] => 401
[header_size] => 0
[request_size] => 237
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.625
[namelookup_time] => 0.060492
[connect_time] => 0.156226
[pretransfer_time] => 0.428025
[size_upload] => 73
[size_download] => 0
[speed_download] => 0
[speed_upload] => 116
[download_content_length] => -1
[upload_content_length] => 73
[starttransfer_time] => 0.624949
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => 2xx.xxx.xx.xx
[certinfo] => Array
(
)
[primary_port] => 443
[local_ip] => 10.10.10.105
[local_port] => 42192
)
==========
the question: how can php curl get and display the failure json response/body in the 401 case?