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:
{"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/"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/firestore/reference/rest/v1/projects.databases.documents/get
https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents/patch
These HTTP requests function correctly when tested in Postman.
AUTH GET ID_TOKENMethod: POSTURL:https://identitytoolkit.googleapis.com/v1/accounts:signInWithPasswordkeys: key -> value:{firebase Web API Key}Body:{"email":"","password":"","returnSecureToken":true}GET FIRESTORE DOCUMENT IFNOMethod: GETURL:https://firestore.googleapis.com/v1/projects/esp-idf-test/databases/(default)/documents/test/testDoc (test is the collection testDoc is the Document)keys: NULLBody: NULLAuthorization: type->Bearer Token Token->{The token_id you got from the AUTH GET ID_TOKEN}PATCH FIRESTORE DOCUMENT IFNOMethod: PATCHURL: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}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.
#include "http_requests.h"char receivedData[4096];char idToken[1950];char client2Header[2000];bool showReceivedData = false;// Event handler function for HTTP client eventsesp_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 passwordvoid 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);}I'm encountering an issue with authenticating using the Bearer token. Any insights or suggestions would be greatly appreciated. Thank you.