Post request in JSON using cURL fails

Viewed 76

I'm struggling to generate a proper JSON POST request using cURL. For that purpose I'm writing a short shell script to do so but apparently there seems to be a problem with my JSON-string (according to the error message I listed below).

If I write the CSR directly into the JSON string, it will work just fine:

authToken="Here'sMyAuthToken"
curl --data-binary '{"authToken" : "'$authToken'", "order" : {"type" : "DomainValidatedCertificateOrder", "csr" : "-----BEGIN CERTIFICATE REQUEST-----
certificaterequestkey
-----END CERTIFICATE REQUEST-----", "adminContact" : {"title" : "mytitle", "firstName" : "myfirstname", "lastName" : "mylastname", "phoneNumber" : "X0000000", "emailAddress" : "test@example.com"}, "techContact" : {"title" : "mytitle", "firstName" : "myfirstname", "lastName" : "mylastname", "phoneNumber" : "000000000", "emailAddress" : "test@example.com"}, "productCode" : "ssl-geotrust-rapidssl-12m", "validationType" : "validateViaDns", "approverEmailAddress" : "postmaster@example.com", "autoRenew" : false}}' -i -X POST https://partner.http.net/api/ssl/v1/json/orderCreate

However, if I pass the CSR over by reading the csr file directly like this

authToken="Here'sMyAuthToken"
csr=$(<csr.csr)
curl --data-binary '{"authToken" : "'$authToken'", "order" : {"type" : "DomainValidatedCertificateOrder", "csr" : "'$csr'", "adminContact" : {"title" : "mytitle", "firstName" : "myfirstname", "lastName" : "mylastname", "phoneNumber" : "X0000000", "emailAddress" : "test@example.com"}, "techContact" : {"title" : "mytitle", "firstName" : "myfirstname", "lastName" : "mylastname", "phoneNumber" : "000000000", "emailAddress" : "test@example.com"}, "productCode" : "ssl-geotrust-rapidssl-12m", "validationType" : "validateViaDns", "approverEmailAddress" : "postmaster@example.com", "autoRenew" : false}}' -i -X POST https://partner.http.net/api/ssl/v1/json/orderCreate

it will give me the following error.

curl: option -----END: is unknown
curl: try 'curl --help' or 'curl --manual' for more information

I've already found a case where someone had the exact same problem like me here:

POST request containing CSR fails in Bash

The user accomplished solving this problem using the jq package. Unfortunately I can't install this package on the machine the script is supposed to run since I'm not allowed to install any packages at all. Could someone give an advice how to solve this problem?

Many thanks in advance!

2 Answers

You are misquoting things in your command line. You're making frequent use of this sort of structure:

'{"somekey": "'$variable'"}'

That means that you're not quoting $somevariable, so if it contains whitespace you're going to end up with a command other than what you expect. You need to quote all your variables, so the above becomes:

'{"somekey": "'"$variable"'"}'

And your full command line is:

curl --data-binary '
  {
    "authToken" : "'"$authToken"'",
    "order" : {
      "type" : "DomainValidatedCertificateOrder",
      "csr" : "'"$csr"'",
      "adminContact" : {
        "title" : "mytitle",
        "firstName" : "myfirstname",
        "lastName" : "mylastname",
        "phoneNumber" : "X0000000",
        "emailAddress" : "test@example.com"
      },
      "techContact" : {
        "title" : "mytitle",
        "firstName" : "myfirstname",
        "lastName" : "mylastname",
        "phoneNumber" : "000000000",
        "emailAddress" : "test@example.com"
      },
      "productCode" : "ssl-geotrust-rapidssl-12m",
      "validationType" : "validateViaDns",
      "approverEmailAddress" : "postmaster@example.com",
      "autoRenew" : false
    }
  }
  ' -i -X POST https://partner.http.net/api/ssl/v1/json/orderCreate

You could simplify things by using a here document instead of trying to embed everything on the command line. That would look like:

curl -i -X POST --data-binary @- https://partner.http.net/api/ssl/v1/json/orderCreate <<EOF
{
  "authToken": "$authToken",
  "order": {
    "type": "DomainValidatedCertificateOrder",
    "csr": "$csr",
    "adminContact": {
      "title": "mytitle",
      "firstName": "myfirstname",
      "lastName": "mylastname",
      "phoneNumber": "X0000000",
      "emailAddress": "test@example.com"
    },
    "techContact": {
      "title": "mytitle",
      "firstName": "myfirstname",
      "lastName": "mylastname",
      "phoneNumber": "000000000",
      "emailAddress": "test@example.com"
    },
    "productCode": "ssl-geotrust-rapidssl-12m",
    "validationType": "validateViaDns",
    "approverEmailAddress": "postmaster@example.com",
    "autoRenew": false
  }
}
EOF

Now you don't need all those quoting tricks.


Here's how I've tested the above solution:

#!/bin/bash

# Use some sort of http debugging service to verify the content
# of the request.
url="https://eny65dku43a4g.x.pipedream.net"

# Create an example CSR
openssl req new -nodes \
  -keyout req.key \
  -out req.csr \
  -subject '/O=Example$Organization+Inc,CN=example.com'

csr=$(<req.csr)
authToken='example+password$here'

curl -i -X POST "$url" --data-binary @- <<EOF
{
  "authToken": "$authToken",
  "order": {
    "type": "DomainValidatedCertificateOrder",
    "csr": "$csr",
    "adminContact": {
      "title": "mytitle",
      "firstName": "myfirstname",
      "lastName": "mylastname",
      "phoneNumber": "X0000000",
      "emailAddress": "test@example.com"
    },
    "techContact": {
      "title": "mytitle",
      "firstName": "myfirstname",
      "lastName": "mylastname",
      "phoneNumber": "000000000",
      "emailAddress": "test@example.com"
    },
    "productCode": "ssl-geotrust-rapidssl-12m",
    "validationType": "validateViaDns",
    "approverEmailAddress": "postmaster@example.com",
    "autoRenew": false
  }
}
EOF

I have been having a very hard time posting. I kept getting Errors when saving.

This is the request and response with a Content-Type: application/json in the HTTP request header:

Content-Length: 540
Content-Type: application/json
Accept: application/json
Accept-Encoding: deflate, gzip, br
Host: eatled.com


BODY={"authToken": "$authToken","order": {"type": "DomainValidatedCertificateOrder","csr": "$csr","adminContact": {"title": "mytitle","firstName": "myfirstname","lastName": "mylastname","phoneNumber": "X0000000","emailAddress": "test@example.com"},"techContact": {"title": "mytitle","firstName": "myfirstname","lastName": "mylastname","phoneNumber": "000000000","emailAddress": "test@example.com"},"productCode": "ssl-geotrust-rapidssl-12m","validationType": "validateViaDns","approverEmailAddress": "postmaster@example.com","autoRenew": false}}

I removed the Content-Type and this is the request and response.
Notice how the header changed to Content-Type: application/x-www-form-urlencoded and how the JSON is in the KEY of the $_POST data as it was received by the Server. When the server sees the form data header it will may process try to process the request as if it were a form. It depends upon how well the API was written.

Content-Length: 540
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Accept-Encoding: deflate, gzip, br
Host: eatled.com

$_POST
array (
  '{"authToken":_"$authToken","order":_{"type":_"DomainValidatedCertificateOrder","csr":_"$csr","adminContact":_{"title":_"mytitle","firstName":_"myfirstname","lastName":_"mylastname","phoneNumber":_"X0000000","emailAddress":_"test@example_com"},"techContact":_{"title":_"mytitle","firstName":_"myfirstname","lastName":_"mylastname","phoneNumber":_"000000000","emailAddress":_"test@example_com"},"productCode":_"ssl-geotrust-rapidssl-12m","validationType":_"validateViaDns","approverEmailAddress":_"postmaster@example_com","autoRenew":_false}}' => '',
)

This is your curl code with all the escape codes and the options reorganized because the you had them generated an error. This is tested, and works.

curl  -i -H "Content-Type: application/json" -X POST http://eatled.com/receiveheader.php --data-binary "{\"authToken\": \"$authToken\",\"order\": {\"type\": \"DomainValidatedCertificateOrder\",\"csr\": \"$csr\",\"adminContact\": {\"title\": \"mytitle\",\"firstName\": \"myfirstname\",\"lastName\": \"mylastname\",\"phoneNumber\": \"X0000000\",\"emailAddress\": \"test@example.com\"},\"techContact\": {\"title\": \"mytitle\",\"firstName\": \"myfirstname\",\"lastName\": \"mylastname\",\"phoneNumber\": \"000000000\",\"emailAddress\": \"test@example.com\"},\"productCode\": \"ssl-geotrust-rapidssl-12m\",\"validationType\": \"validateViaDns\",\"approverEmailAddress\": \"postmaster@example.com\",\"autoRenew\": false}}"
Related