Problem with firebase REST API in esp-idf. Cannot Patch and Get in firestore
Posted: Tue Apr 09, 2024 8:23 pm
I'm encountering an issue with retrieving and updating documents in Firestore via REST API using ESP-IDF. While the HTTP requests function correctly in Postman, I'm unable to replicate the same functionality within ESP-IDF.
I've successfully authenticated and obtained the id token, but when attempting to use it to perform a GET or PATCH request on a Firestore document, I receive the following error as an HTTP response:
My GET HTTP Request includes the Authorization header in the correct format of Bearer {idToken} as specified in the documentation.
You can refer to the Firebase documentation for more details:
https://firebase.google.com/docs/reference/rest/auth
https://firebase.google.com/docs/firestore/use-rest-api
https://firebase.google.com/docs/firest ... uments/get
https://firebase.google.com/docs/firest ... ents/patch
These HTTP requests function correctly when tested in Postman.
Here's the code including Firebase Auth (successfully obtaining the idToken) and Firestore GET HTTP Requests. Ensure ESP is connected to the internet for these functions to work.
I'm encountering an issue with authenticating using the Bearer token. Any insights or suggestions would be greatly appreciated. Thank you.
I've successfully authenticated and obtained the id token, but when attempting to use it to perform a GET or PATCH request on a Firestore document, I receive the following error as an HTTP response:
Code: Select all
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
E (5443) HTTP_CLIENT: This authentication method is not supported: Bearer realm="https://accounts.google.com/"
You can refer to the Firebase documentation for more details:
https://firebase.google.com/docs/reference/rest/auth
https://firebase.google.com/docs/firestore/use-rest-api
https://firebase.google.com/docs/firest ... uments/get
https://firebase.google.com/docs/firest ... ents/patch
These HTTP requests function correctly when tested in Postman.
Code: Select all
AUTH GET ID_TOKEN
Method: POST
URL:https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword
keys: key -> value:{firebase Web API Key}
Body:{"email":"","password":"","returnSecureToken":true}
GET FIRESTORE DOCUMENT IFNO
Method: GET
URL:https://firestore.googleapis.com/v1/projects/esp-idf-test/databases/(default)/documents/test/testDoc (test is the collection testDoc is the Document)
keys: NULL
Body: NULL
Authorization: type->Bearer Token Token->{The token_id you got from the AUTH GET ID_TOKEN}
PATCH FIRESTORE DOCUMENT IFNO
Method: PATCH
URL:https://firestore.googleapis.com/v1/projects/esp-idf-test/databases/(default)/documents/test/testDoc (test is the collection testDoc is the Document)
keys: updateMask.fieldPaths -> value:testString(the name of the string var inside the document testDoc)
Body: {
"fields": {
"testString": {
"stringValue": "helloWorld"
}
}
}
Authorization: type->Bearer Token Token->{The token_id you got from the AUTH GET ID_TOKEN}
Code: Select all
#include "http_requests.h"
char receivedData[4096];
char idToken[1950];
char client2Header[2000];
bool showReceivedData = false;
// Event handler function for HTTP client events
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id)
{
case HTTP_EVENT_ERROR:
printf("HTTP_EVENT_ERROR\n");
break;
case HTTP_EVENT_ON_CONNECTED:
printf("HTTP_EVENT_ON_CONNECTED\n");
break;
case HTTP_EVENT_HEADER_SENT:
printf("HTTP_EVENT_HEADER_SENT\n");
break;
case HTTP_EVENT_ON_HEADER:
printf("HTTP_EVENT_ON_HEADER\n");
break;
case HTTP_EVENT_ON_DATA:
// Find the first occurrence of '}'
const char *end_ptr = strchr((char *)evt->data, '}');
if (end_ptr != NULL)
{
// Calculate the length until the '}' character
size_t length = end_ptr - (char *)evt->data + 1; // Include '}' in the length
// Concatenate only until the '}' character
strncat(receivedData, (char *)evt->data, length);
printf("end_ptr is: %p evt-data is : %p length is :%d \n", end_ptr, (char *)evt->data, length);
}
else
{
// If '}' is not found, just concatenate the entire data
strncat(receivedData, (char *)evt->data, evt->data_len - 1);
}
if (showReceivedData == true){
printf("evt-data is %s", (char *)evt->data);
}
break;
case HTTP_EVENT_ON_FINISH:
printf("HTTP_EVENT_ON_FINISH\n");
break;
case HTTP_EVENT_DISCONNECTED:
printf("HTTP_EVENT_DISCONNECTED\n");
break;
case HTTP_EVENT_REDIRECT:
printf("HTTP_EVENT_REDIRECT\n");
break;
}
return ESP_OK; // Return OK status
}
esp_err_t firestore_get_document(const char *id_token)
{
esp_http_client_config_t config = {
.url = "https://firestore.googleapis.com/v1/projects/esp-idf-test/databases/(default)/documents/test/testDoc",
.method = HTTP_METHOD_GET,
.event_handler = _http_event_handler,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.crt_bundle_attach = esp_crt_bundle_attach,
.buffer_size = 2048,
.buffer_size_tx = 4096, // Adjust buffer size as needed
};
esp_http_client_handle_t client2 = esp_http_client_init(&config);
showReceivedData = true;
// Authentication: Bearer
strlcpy(client2Header, "Bearer ", sizeof(client2Header));
strlcat(client2Header, id_token, sizeof(client2Header));
printf("Header data: %s\n", client2Header);
// Set headers
esp_http_client_set_header(client2, "Authorization", client2Header);
if (!client2)
{
return ESP_FAIL;
}
memset(receivedData, '\0', sizeof(receivedData));
// Perform HTTP request
esp_err_t err2 = esp_http_client_perform(client2);
if (err2 != ESP_OK)
{
printf("problem \n");
}
// Clean up
esp_http_client_cleanup(client2);
return err2;
}
// Function to authenticate with Firebase using email and password
void firebase_authenticate(const char *email, const char *password, const char *api_key)
{
// Configure HTTP client
esp_http_client_config_t config = {
.url = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword",
.method = HTTP_METHOD_POST,
.event_handler = _http_event_handler,
.user_data = NULL,
.auth_type = HTTP_AUTH_TYPE_BASIC,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.crt_bundle_attach = esp_crt_bundle_attach,
};
// Construct JSON payload for authentication
char post_data[150];
snprintf(post_data, sizeof(post_data), "{\"email\":\"%s\",\"password\":\"%s\",\"returnSecureToken\":true}", email, password);
printf("%s \n", post_data);
// Initialize HTTP client
esp_http_client_handle_t client = esp_http_client_init(&config);
// Set content type header
esp_http_client_set_header(client, "Content-Type", "application/json");
char url_with_query[256];
snprintf(url_with_query, sizeof(url_with_query), "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=%s", api_key);
// Set the URL for the HTTP request
esp_http_client_set_url(client, url_with_query);
// Set post data
esp_http_client_set_post_field(client, post_data, strlen(post_data));
printf("\nThe final url with query in order to sign in with email and pass is: \n %s \n", url_with_query);
char *clientHeader;
esp_http_client_get_header(client, "Content-Type", &clientHeader);
printf("The header in order to sign in with email and pass is: \n %s \n", clientHeader);
char *clientPostData;
esp_http_client_get_post_field(client, &clientPostData);
printf("The body in order to sign in with email and pass is: \n %s \n\n", clientPostData);
// Perform HTTP POST request
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK)
{
printf("we are here\n");
// Check if response code is 200 OK
if (esp_http_client_get_status_code(client) == 200)
{
printf("Response code of firebase sign in is OK \n");
cJSON *json = cJSON_Parse(receivedData);
if (json != NULL)
{
cJSON *id_token = cJSON_GetObjectItem(json, "idToken");
if (id_token != NULL)
{
strncpy(idToken, id_token->valuestring, sizeof(idToken));
size_t idToken_len = strlen(idToken);
idToken[idToken_len] = '\0'; // Null-terminate the string again
printf("ID Token: %s\n", idToken);
}
cJSON_Delete(json);
}
}
}
else
{
printf("Something went wrong with client perform");
}
// Clean up HTTP client
esp_http_client_cleanup(client);
printf("calling the HTTP Request \n");
firestore_get_document(idToken);
}