[SOLVED] Unable to send Authorization Bearer header using HTTPPARA USERDATA using GSM SIM808 GPRS POST request

I have GSM SIM808 GPS/GPRS module and BMP280 Barometric Pressure Sensor connected to UNO.


SIMCOMM GSM SIM808 GPS/GPRS Module



GSM Module and BMP280 Barometric Pressure Sensor with UNO




GSM Module External Power Supply



Pin Connections

GSM TX   - UNO GPIO2
GSM RX   - UNO GPIO3
GSM GND  - UNO GND (Common GND)
BMP VIN  - UNO 3.3V
BMP GND  - UNO GND
BMP SCL  - UNO A5
BMP SDA  - UNO A4

GSM External Power Supply
(Smart Plus AC/DC Setup-Box Adapter)
Input : 100-280V ~ AC ~ 50/60 Hz
Output: DC 12V - 1Amp
Max current: 2Amp.



Thinger.io Databucket Setup
I've setup Thinger.io Databucket to recieve data. This requires cURL request

curl \
  -H "Content-Type: application/json;charset=UTF-8" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTE2OTM2MjYsImlhdCI6MTc1MTY4NjQyNiwicm9sZSI6InVzZXIiLCJ1c3IiOiJzdWNoYW5hIn0.2l13Q4l4-GI6Y2QmP6HvsoQdXoIm8OOuYR19F6bD9HY" \
  -H "Accept: application/json, text/plain, */*" \
  -X POST \
  -d '{"lat":40.416775,"lng":-3.70379,"temperature":23.33,"humidity":32.44}' \
  https://backend.thinger.io/v3/users/suchana/devices/GSM/callback/data



cURL POST request sent - Unauthorised Access Error
I'm trying to send request to server from GSM SIM808 module. However, I've encountered unauthorised access error.

{"error":{"message":"unauthorized"}}
Error Code: 1003




Investigation revealed Authorization Bearer header missing
This indicates that required Authorization header missing. To confirm this, I've replaced Thinger.io API endpoint with webhook.site. My temporary URL generated is http://webhook.site/a5997670-50f5-436d-9011-22fe30313400.




Webhook Confirmed same that Authorization header missing

Webhook detected a POST request that is comming from GSM module. On inspection it is confirmed that Authorization header really missing. Here's what I recieved.

Headers

Raw Content

{"temperature":25.0,"pressure":1013.25}



Here is my entire Aurdino UNO code Snippet.

//@author Suchana SpaceExpo
//CubeSat V2 - All Rights Reserved 

#include <SoftwareSerial.h>

#define SIM808_RX 2
#define SIM808_TX 3
SoftwareSerial sim808(SIM808_RX, SIM808_TX);

String apn = "airtelgprs.com";
String bearer = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTE2NjI4MzgsImlhdCI6MTc1MTY1NTYzOCwicm9sZSI6InVzZXIiLCJ1c3IiOiJzdWNoYW5hIn0.Ba14gGeJ5SXKbUvQuO9vOnjavWODLI3tAeQ_h96-s58";
String payload = "{\"temperature\":25.0,\"pressure\":1013.25}";

bool sendAT(String command, String expected, unsigned long timeout = 3000) {
  sim808.println(command);
  Serial.println("> " + command);
  unsigned long start = millis();
  String response = "";
  while (millis() - start < timeout) {
    while (sim808.available()) {
      char c = sim808.read();
      response += c;
      if (response.indexOf(expected) != -1) {
        Serial.println("✓ " + command);
        return true;
      }
    }
  }
  Serial.println("✗ " + command);
  Serial.println("Response: " + response);
  return false;
}
    

void setup() {
  Serial.begin(9600);
  sim808.begin(9600);
  delay(3000);
  Serial.println("Starting SIM808 HTTP POST to Thinger.io...");

  sendAT("AT", "OK");
  sendAT("AT+CGATT=1", "OK");
  //sendAT("AT+CIICR", "OK");

  sendAT("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK");
  sendAT("AT+SAPBR=3,1,\"APN\",\"" + apn + "\"", "OK");

    delay(10000);
    
  for (int i = 0; i < 3; i++) {
    if (sendAT("AT+SAPBR=1,1", "OK", 8000)) break;
    delay(3000);
  }

  sendAT("AT+SAPBR=2,1", "OK");

  //sendAT("AT+HTTPTERM", "OK");   // In case previous session was left open
  sendAT("AT+HTTPINIT", "OK");
  sendAT("AT+HTTPPARA=\"CID\",1", "OK");

  // ✅ Replace domain with IP & add HOST header
  sendAT("AT+HTTPPARA=\"URL\",\"http://webhook.site/a5997670-50f5-436d-9011-22fe30313400\"", "OK");
    sendAT("AT+HTTPPARA=\"CONTENT\",\"application/json\"", "OK");
    
  String headers = "Authorization: Bearer " + bearer + "\r\n";
bool headerOk = sendAT("AT+HTTPPARA=\"USERDATA\",\"" + headers + "\"", "OK");
    sendAT("AT+HTTPPARA=\"UA\",\"curl/7.64.1\"", "OK");
    
    
  // ✅ Headers: Authorization and Content-Type in one USERDATA line

    
    
    /*
  if (sendAT("AT+HTTPPARA=\"USERDATA\",\"Host: api.thinger.io\\r\\nAuthorization: Bearer " + bearer + "\\r\\nContent-Type: application/json\"", "OK")) {
  Serial.println("✓ USERDATA header set");
} else {
  Serial.println("✗ USERDATA header FAILED — Authorization likely missing");
}
    
   */
    

  // ✅ Correct payload length
  int len = payload.length();
  sendAT("AT+HTTPDATA=" + String(len) + ",5000", "DOWNLOAD");
  sim808.print(payload);
  delay(2000);

  // ✅ Post and parse response
// Step 1: Start POST
sim808.println("AT+HTTPACTION=1");
Serial.println("> AT+HTTPACTION=1");

String httpActionResp = "";
unsigned long start = millis();
bool actionReceived = false;

while (millis() - start < 10000) {
  if (sim808.available()) {
    char c = sim808.read();
    httpActionResp += c;
    if (httpActionResp.indexOf("+HTTPACTION:") != -1) {
      actionReceived = true;
      break;
    }
  }
}

Serial.println("HTTPACTION response:");
Serial.println(httpActionResp);

// Step 2: Always read the response body from the server
if (actionReceived) {
  delay(1500); // wait to ensure server finished sending
  sim808.println("AT+HTTPREAD");
  Serial.println("> AT+HTTPREAD");

  delay(1500); // allow response to fill buffer

  String serverResponse = "";
  while (sim808.available()) {
    serverResponse += (char)sim808.read();
  }

  Serial.println("Server Response Body:");
  Serial.println(serverResponse);
} else {
  Serial.println("✗ Didn't receive +HTTPACTION response in time.");
}

  sendAT("AT+HTTPTERM", "OK");
  sendAT("AT+SAPBR=0,1", "OK");
}

void loop() {}




Serial Monitor Output

Here is the output from Serial Monitor for your reference:

00:22:46.710 -> > AT
00:22:46.713 -> ✓ AT
00:22:46.715 -> > AT+CGATT=1
00:22:46.717 -> ✓ AT+CGATT=1
00:22:46.719 -> > AT+SAPBR=3,1,"Contype","GPRS"
00:22:46.746 -> ✓ AT+SAPBR=3,1,"Contype","GPRS"

00:22:46.791 -> > AT+SAPBR=3,1,"APN","airtelgprs.com"
00:22:46.841 -> ✓ AT+SAPBR=3,1,"APN","airtelgprs.com"
00:23:01.830 -> > AT+SAPBR=1,1
00:23:02.654 -> ✓ AT+SAPBR=1,1
00:23:02.657 -> > AT+SAPBR=2,1
00:23:02.726 -> ✓ AT+SAPBR=2,1
00:23:02.729 -> > AT+HTTPINIT
00:23:02.746 -> ✓ AT+HTTPINIT
00:23:02.776 -> > AT+HTTPPARA="CID",1
00:23:02.809 -> ✓ AT+HTTPPARA="CID",1
00:23:02.948 -> thinger.io/v1/users/suchana/devices/GSM/data"
00:23:03.043 -> ✓ AT+HTTPPARA="URL","http://api.thinger.io/v1/users/suchana/devices/GSM/data"

00:23:06.107 -> kely missing
00:23:06.110 -> > AT+HTTPDATA=39,5000
00:23:06.113 -> ✓ AT+HTTPDATA=39,5000
00:23:08.129 -> > AT+HTTPACTION=1
00:23:09.688 -> N:
00:23:11.149 -> > AT+HTTPREAD
00:23:12.778 -> "error":{"message":"unauthorised"}
00:23:12.782 -> > AT+HTTPTERM
00:23:12.785 -> ✓ AT+HTTPTERM
00:23:12.787 -> > AT+SAPBR=0,1
00:23:13.333 -> ✓ AT+SAPBR=0,1

I conclude that Authorization header missing causing this issue. Please refer the part of code that dealing with this.

String bearer = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTE2NjI4MzgsImlhdCI6MTc1MTY1NTYzOCwicm9sZSI6InVzZXIiLCJ1c3IiOiJzdWNoYW5hIn0.Ba14gGeJ5SXKbUvQuO9vOnjavWODLI3tAeQ_h96-s58";
String headers = "Authorization: Bearer " + bearer + "\r\n";
bool headerOk = sendAT("AT+HTTPPARA=\"USERDATA\",\"" + headers + "\"", "OK");

I'm tried multiple times to send Authorization header. But couldn't figure out the issue. Therefore I hereby request you to look into the issue and resolve this. Any help in this regard is highly acknowledged.



Expected
I've expected Authorization Bearer header with access token. But not sent. If sent, our data will be recorded as a new entry or response. Server will return success as JSON response.

{"status": "success"}




Additional Information

The raw data we sent, that can be fetched from following API endpoint. https://api.thinger.io/v1/users/suchana/buckets/GSM/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJHU00iLCJzdnIiOiJhcC1zb3V0aGVhc3QuYXdzLnRoaW5nZXIuaW8iLCJ1c3IiOiJzdWNoYW5hIn0.iQjV-Pb8UDk2nuHr_HQ-S7bDCneZrn-IMBXTEtNJMTE.

Response would look like:

[
  {
    "ts": 1751641094731,
    "val": {
      "pressure": 2568.25,
      "temperature": 5630.5736
    }
  },
  {
    "ts": 1751640375126,
    "val": {
      "pressure": 500.25,
      "temperature": 1000.5736
    }
  },
  {
    "ts": 1751639441922,
    "val": {
      "pressure": 1013.25,
      "temperature": 25
    }
  }
]

This JSON can be parsed and display using interactive Google Charts as depicted below.


But NOTE:
This get updated only when our earlier cURL request with Authorization Bearer header succesful.



Display using Interactive Google Charts
Once if Authorization header sent successfully and data get stored in Thinger.io, will modify the code to send actual BMP280 data every min and display it over a web application using Google Charts. Here's the video: https://drive.google.com/file/d/1EVt3PvdPBg0xklS0fkXEmxrlLFrhfu1w/view?usp=sharing




Conclusion:
No issues in recieving data from Thinger.io and displaying as Google Chart. Issue at sending data from GSM. POST request successful. Raw data being sent. But closure investigation revealed that Authorization Bearer header missing. This needs to be resolved.


EDIT:
Hey there, I found similar issues on this Forum, but interestingly no one responded :face_with_raised_eyebrow:. SIM900A Send HTTP headers and also refer Using header in HTTP request with AT command via SIM800l?

Projects > Networking, Protocols, and Devices
Retired > GSM Shield Projects > General Guidance

Isn't it not possible to send coustom headers using GSM SIM808 module?? Why can't even send Authorization Bearer header? Is there any code related issue or hardware related?

SOLVED
Craft raw HTTP request with desired headers over TCP Connection using AT+CIPSTART and AT+CIPSEND. Only over TCP network, custom headers are allowed including Authorization Bearer <token>. Never use AT+HTTPPARA to set Authorization header. It doesn't allow. Refer specification for more details.

/*--------------------------------------------------------
   CubeSat® - Suchana SpaceExpo
     @author Hemanth Abhiram

      © All Rights Reserved
 --------------------------------------------------------*/


#include <SoftwareSerial.h>
#include <SoftWire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <LiquidCrystal.h>
#include <SD.h>
#include <SPI.h>
#include <LoRa.h>           

#define RX 2
#define TX 3

LiquidCrystal lcd(12, 11, 5,4, 3, 2);
SoftwareSerial sim808(RX, TX);
Adafruit_BMP280 bmp;

String apn = "airtelgprs.com";
String host = "backend.thinger.io";
unsigned long t = 0;
byte d = 0;

bool sendAT(String cmd, String expected, unsigned long timeout = 3000) {
  sim808.println(cmd);
  Serial.println("> " + cmd);
  unsigned long start = millis();
  String response = "";
  while (millis() - start < timeout) {
    while (sim808.available()) {
      char c = sim808.read();
      response += c;
      if (response.indexOf(expected) != -1) {
        Serial.print(F("✓ "));
        Serial.println(cmd);
        return true;
      }
    }
  }
  Serial.println(F("✗ "));
  Serial.println(cmd);
  Serial.println("Response: " + response);
  return false;
}

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  if (!bmp.begin(0x76)) {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  }
    
  sim808.begin(9600);
  delay(2000);
    Serial.println(F("Initializing..."));
  

  sendAT("AT", "OK");
  sendAT("AT+CGATT=1", "OK");

  // 1. Open TCP connection
  sendAT("AT+CIPSHUT", "SHUT OK", 5000);
  sendAT("AT+CIPMUX=0", "OK");
  sendAT("AT+CSTT=\"" + apn + "\"", "OK");
  sendAT("AT+CIICR", "OK", 10000);
  sendAT("AT+CIFSR", ".", 5000);  // IP address  
}

void loop() {
//Read Temperature
  float temperature = bmp.readTemperature();
  Serial.print(F("Temperature = "));
  Serial.print(temperature);
  Serial.println(F(" *C"));

  delay(1000);

//Read Presssure
  float pressure = bmp.readPressure() / 100.0F;
  Serial.print(F("Pressure = "));
  Serial.print(pressure);
  Serial.println(F(" hPa"));
  delay(2000);

//Payload data
   String payload = "{\"temp\":" + String(temperature, 2) + ",\"pre\":" + String(pressure, 2) + "}";
    
  lcd.print("Sending");
  if(millis() - t>=1000){
    t = millis();
    if (d < 3) lcd.print("."), d++;
  }
    
  sendAT("AT+CIPSTART=\"TCP\",\"" + host + "\",80", "CONNECT OK", 10000);
    
 // 3. Send length and then data
  sendAT("AT+CIPSEND", ">", 5000);
String postRequest = "POST /v3/users/suchana/devices/GSM/callback/data HTTP/1.1\r\n";
  sim808.print(postRequest);
  postRequest = "Host:  backend.thinger.io\r\n";
  sim808.print(postRequest);
  postRequest = "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTE3ODAyNjgsImlhdCI6MTc1MTc3MzA2OCwicm9sZSI6InVzZXIiLCJ1c3IiOiJzdWNoYW5hIn0.alYIrIDyBPxPGAlFmlC9rFqb974nnV-mXqJZlELEOuY\r\n";
  sim808.print(postRequest);
  postRequest = "Content-Type: application/json;charset=UTF-8\r\n";
    sim808.print(postRequest);
  postRequest = "Content-Length: " + String(payload.length()) + "\r\n";
    sim808.print(postRequest);
  postRequest = "Connection: close\r\n\r\n";
    sim808.print(postRequest);
  postRequest = payload;
  sim808.print(postRequest);
  delay(3000); // allow data to be sent
  sim808.write(0x1A); // CTRL+Z to send

  // 4. Read response
  delay(5000);
  String response = "";
  while (sim808.available()) {
     Serial.println(F("===== Server Response ====="));
     Serial.println(response);
}
    
 // 5. Close connection
  sendAT("AT+CIPCLOSE", "CLOSE OK");
  delay(60000);
}