ESP32 Arduino: Basic Authentication

The objective of this post is to explain how to send a HTTP GET request using basic authentication on the Arduino core running 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 send a HTTP GET request using basic authentication on the Arduino core running on the ESP32.

In order to test the request, we will develop a very simple server in Python, using the Flask module.

Important: In this tutorial, we are covering only the basic authentication mechanism. This mechanism doesn’t guarantee data privacy and since we are going to use HTTP, the credentials are sent in plain text and can be easily captured by an attacker. Thus, in order to secure the data sent do the server we need to use HTTPS, which guarantees the encryption of the data sent.

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

The Python code

The Python code for this tutorial will be exactly the same we have used in this previous tutorial. Thus, we will not cover it in much detail here.

So, we start by importing all the needed classes and objects from the flask module. Then, we will create an object of the Flask class, which will be the one used to configure the server.

from flask import Flask
from flask import request

app = Flask("my app")

Next we will define the route that will be listening for incoming HTTP GET requests, which we make perform from the ESP32.

In the route handling function, we will access the authorization object from the request to print both the username and the password sent by the client. As stated in the previous post, we can access this object in Python dictionary style.

As answer to the request we will return a simple “ok” message.

@app.route('/auth')
def authRouteHandler():

    print(request.authorization["username"])
    print(request.authorization["password"])

    return "ok"

To finalize the code, we need to call the run method on our previously created app object, so the server starts listening for incoming requests.

This method allows us to configure both the IP and the port where the server will be listening (host and port arguments, respectively). We will configure the server to listen on all available interfaces by using the “0.0.0.0” IP. As port, we will use 8090.

The full source code can be seen below.

from flask import Flask
from flask import request

app = Flask("my app")

@app.route('/auth')
def authRouteHandler():

    print(request.authorization["username"])
    print(request.authorization["password"])

    return "ok"

app.run(host = '0.0.0.0', port = 8090)

Testing the server code

Since we are developing an end to end system composed of two distinct parts that may have errors, my recommendation is that you perform a quick test to the Flask server after finishing the code, before starting making requests with the ESP32. This way, we can find possible problems on the server beforehand.

I’m assuming that both the ESP32 and the machine that is running the Flask server are on the same WiFi network, so we can reach the server by the local IP address of the machine.

In order to reach the Flask server from outside the WiFi network, we would need to do port forwarding on the router in order for it to forward packets received on its public address to a specific local address (the one from the machine running the Flask app). Since this is a more advanced procedure that depends on the router model, we will not cover it here.

So, the first thing we need to do is finding the local IP of the machine that is running the Flask server. You can obtain it in the command line with the ipconfig command on Windows and the ifconfig command on Linux. Alternatively, you can obtain it from this online tool.

Next we need to run our Flask code. You can do it, for example, from IDLE, the IDE that comes by default with the Python installation. Another really good Python IDE that you can use is PyCharm.

After that, we can use a tool like Postman to perform a request with basic authentication. To do it, just open Postman and on the URL text box enter the endpoint below, changing #yourMachineIP# by the local IP of the computer that is running the Flask server.

http://#yourMachineIp#:8090/auth

On the methods dropdown (letf of the URL text box), select GET. Then, click on the authorization tab and on the Type dropdown select Basic Auth.

To finalize, on the username and password text boxes insert some values of your choice. Then, send the request.

You can check below at figure 1 the configuration areas mentioned highlighted in the Postman app. Also as illustrated, upon executing the request, you should get a “ok” message as response from the server.

Postman basic auth sent to flask server.png

Figure 1 – Testing the Flask server standalone with Postman.

If you go to the Python prompt where the Flask server is running, you should get an output similar to figure 2, which shows the credentials we have used on Postman getting printed.

Flask server auth request from Postman.png

Figure 2 – Flask server printing the credentials from the request sent by Postman.

The Arduino code

Most of the Arduino code is based on this previous tutorial, which explains how to perform HTTP GET requests from the ESP32, with some modifications to include the basic authentication part.

As usual with all the code that involves connecting the ESP32 to a WiFi network, we start by including the WiFi.h library. We will also need the HTTPClient.h library for being able to send the HTTP requests with an easy to use higher level API.

Since for the basic authentication header we need to send the password and the username as a base64 string, we will also include the base64.h library. For a detailed tutorial on how to use it in the ESP32, please check here.

In order to be able to connect to the WiFi network, we will declare both the network name (SSID) and the password as global variables, so we can easily change them.

To finalize this section of the code, we will also declare the username and the password we are going to use in the request as two global String variables. You can use the values you want for both variables, since the server will only print them.

#include "WiFi.h"
#include "HTTPClient.h"
#include "base64.h"

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

String authUsername = "testEsp32USer";
String authPassword = "testEsp32Pass";

The Arduino setup function will be used to open a serial connection and to connect the ESP32 to the WiFi network.

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

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

  Serial.println("Connected to WiFi");

}

We will perform the HTTP GET requests periodically in the Arduino loop function. First we will need an object of class HTTPClient, which has the methods needed to make the request.

HTTPClient http;

Then, we need to call the begin method on the HTTPClient object, passing as input a string with the endpoint to which we want to send the request to. In our case, we will use the same endpoint we have tested before in Postman:

 
http://#serverLocalIP#:8090/auth

Note that in the code below I’m using my server’s local IP and yours will most likely be different.

http.begin("http://192.168.1.88:8090/auth");

For the basic authentication mechanism, we need to set the Authorization header with the username and the password, in the following format (the underlined part is sent in base64 encoding):

Authorization: Basic username:password

So we will first build the base64 string from the password and username variables we declared in the beginning of the code.

In order to obtain the base64 encoding of a string, we can use the encode static method of the base64 class, which receives as input the string to encode and returns the base64 encoded result.

Since the encode method is static, we can access it using the class name and the C++ scope resolution operator (::).

String auth = base64::encode(authUsername + ":" + authPassword);

Now that we have the base64 encoded part of the Authorization header, we simple need to concatenate it to the “Basic “ string and set it as the Authorization header of the request.

In order to add a header to the request, we need to call the addHeader method of the HTTPClient object.

This method receives as first argument the name of the header, which is “Authorization”. As second argument, it receives the content of that header.

http.addHeader("Authorization", "Basic " + auth);

To send the actual request, we simply need to call the GET method of the HTTPClient object. This method will return as output the HTTP response code from the server, which we will store for error validation.

int httpCode = http.GET();

If the returned value is greater than zero, then it is a HTTP response code from the server. If it is lesser than zero, then it corresponds to an internal error on the ESP32.

In case of success, we will obtain the response from the server by calling the getString method of the HTTPClient object.

We will then print this response and the HTTP code returned. We should obtain “ok” and 200, respectively.

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");
}

After processing the request answer, we should call the end method of the HTTPClient object, in order to free the resources.

http.end();

The final complete source code can be seen below. Note that we have added a validation to check if the ESP32 is still connected to the WiFi network before sending the request, and a 10 seconds delay between each iteration of the Arduino loop.

#include "WiFi.h"
#include "HTTPClient.h"
#include "base64.h"

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

String authUsername = "testEsp32USer";
String authPassword = "testEsp32Pass";

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

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

  Serial.println("Connected to WiFi");

}

void loop() {

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

    HTTPClient http;

    http.begin("http://192.168.1.88:8090/auth");

    String auth = base64::encode(authUsername + ":" + authPassword);
    http.addHeader("Authorization", "Basic " + auth);

    int httpCode = http.GET(); 

    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();
  }

  delay(10000);

}

Testing the whole system

Since we have already tested the Flask server in the previous section, we can now try to test the end-to-end system.

Thus, the next step is to compile and upload the Arduino code to the ESP32 using the Arduino IDE.

After the procedure finishes, open the serial console and wait for the connection to the WiFi network to be established. After that, the ESP32 should start to send the requests to the Flask server periodically.

If you go back to the Python prompt, you should get an output similar to figure 3, which shows the credentials sent in the request from the ESP32 getting printed.

Flask server auth request from ESP32.png

Figure 3 – Flask server printing the credentials sent by the ESP32.

Related posts

 

 

Advertisements

5 Replies to “ESP32 Arduino: Basic Authentication”

  1. Good evening, premise I’m a beginner with arduino, I wanted to test the scratch you proposed but when I check the code is reported the error
    “HTTPClient ‘was not declared in this scope”.
    I hope in your help

    Liked by 1 person

    1. Hi!

      Thanks for the feedback 🙂

      Yes you are right, I didn’t see that function at the time xD

      Nonetheless hopefully this is still useful so people can see what happens under the hood for the basic authentication, more precisely the need to do the base64.

      Best regards,
      Nuno Santos

      Like

  2. Thank you for this article! You don’t need to set the auth header manually. You can call the method setAuthorization() of the httpclient-class and pass the username and pw as parameters. 🙂

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s