ESP32 Arduino: HTTPS GET Request

The objective of this post is to explain how to perform a GET request over HTTPS using the Arduino core on the ESP32. The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


Introduction

The objective of this post is to explain how to perform a GET request over HTTPS using the Arduino core on the ESP32.

Explaining in detail how HTTPS works is outside the scope of this post. So, basically HTTPS is the secure version of HTTP, meaning that the data exchanged between the server and the client is encrypted [1].

In order to establish a HTTPS connection, the server needs to provide its digital certificate, which contains its public encryption key, needed for the initial protocol handshake [1].

Nonetheless, it’s important to note that usually clients don’t know if the certificate of the server they are trying to reach is valid, meaning that they don’t know if they can trust it.

So, the certificate validation procedure checks who issued the certificate of the server we are connecting to. Then, it checks the issuer’s certificate and if we still don’t trust it, we go up another level and so on, building a certificate chain.

At some point we need to trust someone. Usually, clients trust in the Root CAs, which are at the top of the certification chain [2]. For instance, browsers have a list of CAs that they will trust when found on the certification chain. You can check here an example for Mozilla.

So, since we are going to perform our request from the ESP32 and not from a browser, this means we will need to specify the Certificate of a Certification Authority we trust for validating the certification chain for the website we are trying to reach. We will see below how to get the needed certificate.

The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.

 

Getting the certificate of the Root CA

In order to perform our tests, we will contact a fake online REST API website, which is available over HTTPS. You can check here, using a web browser, the endpoint we are going to reach and confirm the information that should be returned.

To get the Certificate of the Root CA, an easy way is to access the website on Firefox and click the lock icon at the left of the URL, as can be seen at figure 1.

Note also that this endpoint of the API will return some JSON content, which should match the data received later on the Arduino program.

Firefox check certificate chain.png

Figure 1 – Checking certificates on Firefox.

Then on the popup that appears you need to click the arrow highlighted in figure 2.

Firefox certificate popup arrow.png

Figure 2 – Firefox certificate popup.

Then you should click on “More information” (my browser is in Portuguese), as highlighted in figure 3.

Firefox more information certificate.png

Figure 3 – Firefox certificate more information.

Now a new popup should open. There, click in the “View certificate” button, highlighted in figure 4.

Firefox view certificate popup

Figure 4 – View certificate popup.

Again, a new popup should open. On the tabs on the top, select “Details”. Then, you should get to a tab with a box titled “Certificate hierarchy”, as indicated in figure 5.

This box shows the certificate chain all the way up to a Root CA in which the browser trusts. Select it and on the bottom of the popup click on the “Export” button, so we can get the certificate to use on the ESP32.

Firefox certificate chain popup.png

Figure 5 – Certificate chain popup.

Upon clicking the button, save it somewhere on your computer. After that, open it with a text editor such as Notepad++. You should get a result similar to figure 6.

Fake online API website root CA

Figure 6 – Certificate of the root CA for the test API website.

Now we must convert it to a Arduino multi-line string, so we can use it in our program. You can check below the final format, for an easy copy and paste. You can check here a trick on Notepad++ to do vertical selections, for easily pasting the extra characters needed to turn the certificate in a Arduino multi-line string.

const char* root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\n" \
"MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" \
"BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\n" \
"IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\n" \
"MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\n" \
"ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\n" \
"T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\n" \
"biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\n" \
"FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\n" \
"cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\n" \
"BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" \
"BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\n" \
"fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\n" \
"GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n" \
"-----END CERTIFICATE-----\n";


The Code

We will start our code by including the necessary libraries. We will include the WiFi.h library, which is needed for connecting the ESP32 to a WiFi network. We will also need the HTTPClient.h library, which will make available the class needed to perform the request.

#include <WiFi.h>
#include <HTTPClient.h>

We will also need to declare two variables to hold both the WiFi network name (ssid) and password, which are needed to connect to it.

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

Finally, we will need to paste here the CA certificate we just fetched in the previous section.

const char* root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\n" \
"MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" \
"BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\n" \
"IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\n" \
"MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\n" \
"ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\n" \
"T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\n" \
"biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\n" \
"FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\n" \
"cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\n" \
"BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" \
"BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\n" \
"fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\n" \
"GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n" \
"-----END CERTIFICATE-----\n";

Moving on to the setup function, we will open a serial connection to output the results of our program. Then, we will connect the ESP32 to a WiFi network, using the previously declared credentials. You can check on this previous post a detailed explanation on how to connect to a WiFi network.

The full code for the setup function, which already includes the mentioned configurations, can be seen below.

void setup() {

  Serial.begin(115200);
  delay(1000);

  WiFi.begin(ssid, password); 

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");
}

We will establish the connection to the server and make the request on the Arduino main loop function.

We start by declaring an object of class HTTPClient, which will expose the methods needed to perform the request.

HTTPClient http;

Then we will call the begin method on our HTTPClient object, passing as first input the URL to which we want to make the request and as second input the root CA certificate we declared as a global variable.

This will perform the necessary initialization before we can proceed with sending the request.

Please note that the URL should have the HTTPS prefix, since we are doing an HTTPS request rather that using regular HTTP.

http.begin("https://jsonplaceholder.typicode.com/posts?userId=1", root_ca); //Specify the URL and certificate

Now, to perform the actual HTTPS GET request, we simply call the GET method on our HTTPClient object.

This method call will return an integer. If its value is greater than zero, it will correspond to the HTTP code returned by the server. If it is lesser than 0, then it corresponds to an internal error on the ESP32.

int httpCode = http.GET();

So, if the code is indeed greater than zero, we can obtain the payload of the answer returned by the server by calling the getString method of the HTTPClient object. As the name indicates, it will return a string with the response payload.

We will then print both the payload and the HTTP code.

if (httpCode > 0) { //Check for the returning code

   String payload = http.getString();
   Serial.println(httpCode);
   Serial.println(payload);
}

else {
   Serial.println("Error on HTTP request");
}

Finally, we free the resources with a call to the end method on the HTTPClient object.

http.end(); //Free the resources

The final source code can be seen below. It also includes a validation to check if we are still connected to the WiFi network before proceeding with the request.

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";

void setup() {

  Serial.begin(115200);
  delay(1000);

  WiFi.begin(ssid, password); 

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");
}

const char* root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\n" \
"MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" \
"BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\n" \
"IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\n" \
"MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\n" \
"ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\n" \
"T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\n" \
"biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\n" \
"FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\n" \
"cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\n" \
"BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" \
"BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\n" \
"fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\n" \
"GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n" \
"-----END CERTIFICATE-----\n";

void loop() {

  if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status

    HTTPClient http;

    http.begin("https://jsonplaceholder.typicode.com/posts?userId=1", root_ca); //Specify the URL and certificate
    int httpCode = http.GET();                                                  //Make the request

    if (httpCode > 0) { //Check for the returning code

        String payload = http.getString();
        Serial.println(httpCode);
        Serial.println(payload);
      }

    else {
      Serial.println("Error on HTTP request");
    }

    http.end(); //Free the resources
  }

  delay(10000);
}


Testing the code

To test the code, simply compile it and upload it to your ESP32 board using the Arduino IDE. Then open the serial monitor and check the result.

You should get an output similar to figure 7, which shows the response of the GET request getting printed to the serial monitor. This content matches the one we obtain if we access the website using a web browser.

ESP32 Arduino HTTPS request GET

Figure 7 – Output of the HTTPS GET request.


References

[1] https://www.instantssl.com/ssl-certificate-products/https.html

[2] https://support.dnsimple.com/articles/what-is-ssl-root-certificate/


Related content

44 thoughts on “ESP32 Arduino: HTTPS GET Request”

  1. I’ve tried an exact copy/paste and got the same “Error on HTTP request” error.
    Used two ESP32 boards, one with ESP-WROOM-32, and same result.
    What could be the problem? Is there any debug tip you would suggest?

  2. I’ve tried an exact copy/paste and got the same “Error on HTTP request” error.
    Used two ESP32 boards, one with ESP-WROOM-32, and same result.
    What could be the problem? Is there any debug tip you would suggest?

  3. Maybe this will help, was the verbose error:
    Connected to the WiFi network
    [D][HTTPClient.cpp:138] beginInternal(): [HTTP-Client][begin] url: https://jsonplaceholder.typicode.com/posts?userId=1
    [D][HTTPClient.cpp:179] beginInternal(): [HTTP-Client][begin] host: jsonplaceholder.typicode.com port: 443 url: /posts?userId=1
    [I][ssl_client.cpp:46] start_ssl_client(): Free heap before TLS 165576
    [I][ssl_client.cpp:48] start_ssl_client(): Starting socket
    [I][ssl_client.cpp:76] start_ssl_client(): Seeding the random number generator
    [I][ssl_client.cpp:85] start_ssl_client(): Setting up the SSL/TLS structure…
    [I][ssl_client.cpp:98] start_ssl_client(): Loading CA cert
    [I][ssl_client.cpp:154] start_ssl_client(): Performing the SSL/TLS handshake…
    [E][ssl_client.cpp:26] handle_error(): SSL – A fatal alert message was received from our peer
    [E][ssl_client.cpp:28] handle_error(): MbedTLS message code: -30592
    [E][WiFiClientSecure.cpp:102] connect(): lwip_connect_r: 11
    [I][ssl_client.cpp:193] stop_ssl_socket(): Cleaning SSL connection.
    [D][HTTPClient.cpp:831] connect(): [HTTP-Client] failed connect to jsonplaceholder.typicode.com:443
    [D][HTTPClient.cpp:1109] returnError(): [HTTP-Client][returnError] error(-1): connection refused
    Error on HTTP request

    1. Hi!

      I haven’t had the chance to test it now, but there are a couple of reasons that may be causing the error:
      – They may have changed the certificate. Did you use the one already in the source code or did you follow the whole procedure to obtain it?
      – There may be some bug in the Arduino core version you are using. Did you pull the latest changes?

      These are just two guesses of what may have happened. Other than that I need to take a look and investigate, I will try to find some time to do it, but if anyone else has encountered this problem and was able to determine the cause let us know 🙂

      Let me know if some of this was causing the problem.

      Best regards,
      Nuno Santos

  4. Maybe this will help, was the verbose error:
    Connected to the WiFi network
    [D][HTTPClient.cpp:138] beginInternal(): [HTTP-Client][begin] url: https://jsonplaceholder.typicode.com/posts?userId=1
    [D][HTTPClient.cpp:179] beginInternal(): [HTTP-Client][begin] host: jsonplaceholder.typicode.com port: 443 url: /posts?userId=1
    [I][ssl_client.cpp:46] start_ssl_client(): Free heap before TLS 165576
    [I][ssl_client.cpp:48] start_ssl_client(): Starting socket
    [I][ssl_client.cpp:76] start_ssl_client(): Seeding the random number generator
    [I][ssl_client.cpp:85] start_ssl_client(): Setting up the SSL/TLS structure…
    [I][ssl_client.cpp:98] start_ssl_client(): Loading CA cert
    [I][ssl_client.cpp:154] start_ssl_client(): Performing the SSL/TLS handshake…
    [E][ssl_client.cpp:26] handle_error(): SSL – A fatal alert message was received from our peer
    [E][ssl_client.cpp:28] handle_error(): MbedTLS message code: -30592
    [E][WiFiClientSecure.cpp:102] connect(): lwip_connect_r: 11
    [I][ssl_client.cpp:193] stop_ssl_socket(): Cleaning SSL connection.
    [D][HTTPClient.cpp:831] connect(): [HTTP-Client] failed connect to jsonplaceholder.typicode.com:443
    [D][HTTPClient.cpp:1109] returnError(): [HTTP-Client][returnError] error(-1): connection refused
    Error on HTTP request

    1. Hi!
      I haven’t had the chance to test it now, but there are a couple of reasons that may be causing the error:
      – They may have changed the certificate. Did you use the one already in the source code or did you follow the whole procedure to obtain it?
      – There may be some bug in the Arduino core version you are using. Did you pull the latest changes?
      These are just two guesses of what may have happened. Other than that I need to take a look and investigate, I will try to find some time to do it, but if anyone else has encountered this problem and was able to determine the cause let us know 🙂
      Let me know if some of this was causing the problem.
      Best regards,
      Nuno Santos

  5. Reblogged this on Blogger Brothers and commented:
    If you haven’t yet figured it out. I’m a big fan of TechTorialsX – the stuff he likes is very clearly many of my own interests, and I often find myself on his site when I need to figure things out.

    This is yet another example – I ran across his site when needing to explain to another – how to make HTTPs calls, and needed to add a link.

    Good job TechtutorialsX!

  6. Reblogged this on Blogger Brothers and commented:
    If you haven’t yet figured it out. I’m a big fan of TechTorialsX – the stuff he likes is very clearly many of my own interests, and I often find myself on his site when I need to figure things out.
    This is yet another example – I ran across his site when needing to explain to another – how to make HTTPs calls, and needed to add a link.
    Good job TechtutorialsX!

  7. I’ve followed your guide step by step but it doesn’t work (gives http error).
    I’m on the latest library and using a STAMP PICO ESP32 board.
    However if I remove the root_ca parameter from the begin() then it works.
    Unfortunately the same program lines in my application works only once (at the first time) and after that always gives connection refused error.

Leave a Reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading