FirebaseExtended / firebase-arduino

Arduino samples for Firebase.
Apache License 2.0
945 stars 494 forks source link

Implement support for token based auth #224

Open RICK0707 opened 7 years ago

RICK0707 commented 7 years ago

Since Database secret are now being deprecated would it be possible to use new token generation. Can it be done on ESP8266 ? -> Database secrets are currently deprecated and use a legacy Firebase token generator. Update your source code with the Firebase Admin SDK.

andreask1 commented 7 years ago

+1 for authentication with Firebase using password-based accounts

gayanpathirage commented 7 years ago

You may find it here http://stackoverflow.com/questions/37418372/firebase-where-is-my-account-secret-in-the-new-console

However, please develop this feature as database secret support is deprecated

phamtankhai2202 commented 7 years ago

Hi, i have same issue. I can't use token to connect firebase database... Can i help me?

atiqsamtia commented 7 years ago

Have you any plans to implement Token based Auth ? The issue is open from Last 2.5 Months 👎

proppy commented 7 years ago

Sorry for the late follow-up

It seems that the REST API only support OAuth2.0 based auth, see https://firebase.google.com/docs/reference/rest/database/user-auth

In order to support it in the library we would need to:

client_id=...& client_secret=...& refresh_token=...& grant_type=refresh_token

francois1144 commented 7 years ago

Will the new token based authentication be implemented in the future release?

proppy commented 7 years ago

Just found https://github.com/yutter/ArduinoJWT, which could make it easier implement Service account support directly on the ESP.

antonclaeys commented 7 years ago

Can you please elaborate on how to use this? I'm new to this authorization thing and its very confusing. I'm afraid that once the database secrets are fully deprecated, my software won't work anymore, so I'd like to implement token authorization as soon as possible.

ghost commented 7 years ago

Hi there, new to the rep and have been playing around with the library but also running into this authentication issue. Trying to set up a home control system that allows different people in my house to control ESP-based switches, but want to use user-based auth to limit access only to a subset of the database (e.g. those switches they're authorized to access). Seems well documented on the firebase side but this library can't handle authentication beyond the deprecated database secret. Very willing to help out with the issue but not sure where to start. :/ Cheers David

proppy commented 7 years ago

@davido1992 thanks for reaching out, I think a proper solution for this would be to either use oauth2 end user credentials or a jwt service account.

Sadly it looks like Firebase Admin custom token don't really work with the REST API.

fabricio-stein commented 7 years ago

@proppy, can you elaborate on how to use OAuth 2.0 on esp? Is it doable with a 3rd party library or something? I intend to make an authentication with esp on firebase and create an user there, the same way I'd do with an iOS app or Android app. Thanks.

antcosic commented 7 years ago

Does anybody have a working example of esp8266 connected to firebase?

beratuslu commented 7 years ago

@proppy can you provide end user credentials example please?

proppy commented 7 years ago

@beratuslu we would need to implement some refresh logic using the oauth2 endpoint: https://developers.google.com/identity/protocols/OAuth2InstalledApp#offline

rjga94 commented 6 years ago

Any news about this issue ?

beratuslu commented 6 years ago

@proppy please can you provide example...

proppy commented 6 years ago

Hi @beratuslu,

As described in https://github.com/firebase/firebase-arduino/issues/224#issuecomment-273981906 I think we should modify https://github.com/firebase/firebase-arduino/blob/master/src/Firebase.cpp#L91 to refresh the get a new refresh token when it expires.

Something like this could work:

http_->setReuseConnection(true);
http_->begin('www.googleapis.com', '/oauth2/v4/token');
http_->sendRequest('POST', 'client_id=...&client_secret=...&refresh_token=...&grant_type=refresh_token');

And then insert the new access token in the Authorization header or in the query string (if the former doesn't work).

sergioldr commented 6 years ago

@proppy Is the firebase-arduino library modified to use oauth2 instead and no secret key?

kotl commented 6 years ago

@proppy what if we generate access token from service accounts using a custom cloud function? they are free to use to certain amount. it is not ideal solution since you still need to authenticate yourself to the cloud function in some way (which could be a shared secret given as parameter), but that should be a choice of the user of this library.

proppy commented 6 years ago

@kotl I think we need something that the device can refresh.

Either by reusing the jwt Arduino integration from @gguuss Cloud IoT Core library or embededing end users credentials (refresh_token) on the device and implementing OAuth2 refresh: https://developers.google.com/identity/protocols/OAuth2InstalledApp#offline

I'd be in favor of the former as it allow to give device a dedicated identity (service account)

eberlemartin commented 6 years ago

In order to support it in the library we would need to: -replace ?auth= with ?access_token -embed client_id, client_secret in the sketch -use a third-party tool (ex: oauth2playground) to initialily generate the access_token/refresh_token pair -embed the refresh_token in the sketch -implement the refresh logic in the library since access_token expire after 1 hour

I think the questions of creating Oauth tokens and using them should be kept separate. The suggested changes from @proppy would enable this project to use a provided token instead of a db secret.

How you get them does not matter for the implementation and can be determined at a later point.

WilkoV commented 6 years ago

Any news on this topic?

gpsgui commented 6 years ago

Any news about it? It's a core feature, with the lack of it even the simplest integration between arduino and firebase would not be possible. I'm praying for the guys who knows/can implement this feature = ]

Aar0nC commented 6 years ago

+1 this feature is a must-have!

kotl commented 6 years ago

@proppy

I've started exploring how can we get there. Managed to get ID token and then authenticated REST request to RTDB, generated through NodeJS, but without using anything from Firebase Admin / Client SDK. This means that we just need to translate this code into Arduino C++ and use ArduinoJWT library and one https request to get idToken. This simulates generation of custom tokens on the server side and then using signInWithCustomToken on client side, but all done on the client instead. I still believe a better way would be to do this through a Cloud Function that accepts parameters like email/password for generating access token, but we can probably support both methods eventually since once you have id token, it works.

In this sample you will need to copy sample_data.js into data.js and provide appropriate fields. https://github.com/kotl/firebase-arduino/tree/AUTH/contrib/auth Run 'node auth_jwt.js > test.sh' and then 'sh test.sh' will retrieve data from RTDB.

Updated July 15: turns out, we don't need to create tokens if we decide to use only email/password auth. In a new sample I made: https://github.com/kotl/firebase-arduino/blob/AUTH/contrib/auth/auth_email.js A simple https request to identity toolkit is all you need to mint idToken.

proppy commented 6 years ago

@kotl but we still to implement refresh for the token as well?

rasulovk commented 6 years ago

@kotl

Hi, could you explain implementation of you method, where i should add this auth_email.js ? into the project or upload to Firebase ? Thanks in advance.

crashless commented 5 years ago

I would love for this to work - is there anything I can do to help?

yhua537 commented 5 years ago

Edited: After googling more about firebase and cloud function, I agreed with @kotl that using signInWithCustomToken will be the best solution, as we can get away with forgotten password or stupid password. IMHO, the authentication can be done from app/service/web, like many said, it doesn't matter once have the first token, but can be done possibly with these steps:

  1. App in Mobile/pc connect to the device, authenticate the user.
  2. App get the initial token (via createCustomToken(id)) or pick it up from the file as part of sketch
  3. App save initial token (and maybe device id) and also to ESP if wasn't there
  4. Esp connects to firebase with the initial token (and maybe device id)

Does anyone know how to get this library to work with a initial token for now? Has been playing around with @proppy 's suggestion but don't seem to work.

EgHubs commented 3 years ago

Any news :(

gguuss commented 3 years ago

No updates on this currently. You may want to take a look at Google Cloud IoT Core's Arduino client which can interface with Firebase.

EgHubs commented 3 years ago

In case anyone needs it This great library solved the problem by auth with email and password

engrkhan commented 3 years ago

In case anyone needs it This great library solved the problem by auth with email and password

I have tried, it doesn't work.

The error I get is: "Error in get, API key not valid. Please pass a valid API key."

mobizt commented 3 years ago

@engrkhan

The error is the Firebase server authentication error.

You should use the Web API key that belongs to the selected project in the project settings. You can read this doc where to get the Web API key.

If you have the question, please open the issue there.

engrkhan commented 3 years ago

@mobizt

Thanks for the reply.

Yes, the problem is not with the library. It worked great on ESP8266 when I used the Web API key and my email credentials in the following example: https://github.com/mobizt/Firebase-ESP8266/tree/master/examples/Authentications/Email_Password

I could do both set and get operations in my Firebase RTDB.

Surprisingly when I run the same code on my ESP32, it fails quoting the reason "Permission Denied". I am trying hard but couldn't resolve it till now. I will open a new issue.

Thanks again.

mobizt commented 3 years ago

@engrkhan

Please update the Firebase-ESP32 library and try again because the latest version of ESP8266 and ESP32 Firebase libraries are using the same source code.

engrkhan commented 3 years ago

@mobizt

Both the libraries are up-to-date.

Just confirming: Firebase Arduino Client Library for ESP8266 and ESP32, Version 2.0.10 Firebase ESP32 Client: Version 3.8.19

Still getting the error on ESP32: Set int test... FAILED REASON: Permission denied

ESP8266 is good: Set int test... PASSED PATH: /FirebaseIOT/tyW*****883/humidity TYPE: int ETag: 7ysMph9WPitGP7poMnMHMVPtUlI= VALUE: 0

mobizt commented 3 years ago

@engrkhan

Are you using the same code in both library?

Please try below simple code for both ESP32 and ESP8266.


#if defined(ESP32)
#include <WiFi.h>
#include <FirebaseESP32.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#endif

#define FIREBASE_HOST "xxxxxxxxxxxxx.firebaseio.com"
#define API_KEY "xxxxxxxxxxxxxxxxxx"

#define USER_EMAIL "xxxxxxx@gmail.com"
#define USER_PASSWORD "xxxxxxx"

#define WIFI_SSID "xxxxxxxxxx"
#define WIFI_PASSWORD "xxxxxxxxxxxx"

FirebaseAuth auth;

FirebaseConfig config;

FirebaseData fbdo;

void tokenStatusCallback(TokenInfo info);

void setup()
{
  Serial.begin(115200);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(300);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  config.host = FIREBASE_HOST;
  config.api_key = API_KEY;

  auth.user.email = USER_EMAIL;
  auth.user.password = USER_PASSWORD;

  config.token_status_callback = tokenStatusCallback;

  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);

}

void tokenStatusCallback(TokenInfo info)
{
  if (info.status == token_status_error)
  {
    Serial.printf("Token error code: %d, message: %s\n", info.error.code, info.error.message.c_str());
  }
  if (info.status == token_status_ready)
  {
    if (Firebase.setString(fbdo, "/Test123", "Hello World! " ))
    {
      Serial.println("store data ok");
    }
    else
    {
      Serial.println("error, " + fbdo.errorReason());
      Serial.println("------------------------------------");
      Serial.println();
    }
  }
  else
  {
    Serial.printf("Token status code: %d\n", info.status);
  }
}

void loop()
{
}
mobizt commented 3 years ago

@engrkhan

In ESP32 which supports multitasking, you may need to wait for the token generation to be ready before calling the Firebase functions.

Before calling the Firebase functions, just use this to check the ready state of token.

TokenInfo info = Firebase.authTokenInfo();
if (info.status == token_status_ready)
{
   //Do your Firebase calls.
}

or simpler

if (Firebase.authTokenInfo().status == token_status_ready)
{
   //Do your Firebase calls.
}
engrkhan commented 3 years ago

@mobizt

I have tried both ways i.e., using Firebase_ESP_Client.h for both ESP8266 and ESP32, and their individual libraries as you suggested (please see the code start below). I still get the same problem: Permission denied.

/***********Original example: File -> Examples -> Firebase Arduino Client -> Authentications -> Email_Password
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <Firebase_ESP_Client.h>
*/

//************* As suggested by @mobizt 24/03/2021 on github issue#224.#if defined(ESP32)
#include <WiFi.h>
#include <FirebaseESP32.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#endif

/* 1. Define the WiFi credentials */
#define WIFI_SSID "xxxxxxxxxx"
#define WIFI_PASSWORD "xxxxxxxxxxx"
.
.
.

Ultimately I tried it using the FirebaseJson object and it worked fine on ESP32. I must give credit to the following link: https://www.electroniclinic.com/esp32-firebase-tutorial-send-sensor-data-to-google-firebase-database/

Thanks again for your time and help. I appreciate it greatly.

mobizt commented 3 years ago

@engrkhan

Did you try the code I provide above comment?

Permission denied is because the id token was not ready or invalid when you call the Firebase.

engrkhan commented 3 years ago

@mobizt

Yes, I do check the ready state of the token before I update the RTDB. The code that you have suggested in your comment is already being part of the example that I am trying: https://github.com/mobizt/Firebase-ESP32/tree/master/examples/Authentications/Email_Password

Still getting "Permission Denied".

mobizt commented 3 years ago

@engrkhan

I'll confirm the test yesterday that ESP32 and the library test is ok.

I create a fresh new Gmail account, and use it to create the new project, create new RTDB database, enable Email/Password provider, create the project user with email and password.

The RTDB security rules are set to allow read and write in the test mode.

Copy the Web API key, database host (from the RTDB console) and user Email and password to the sketch and test with ESP32 without problem.

In your case, if you sure you never missed these setup steps, please try a different ESP32 device and WiFi internet access point.

Aishwarya19966 commented 3 years ago

Here is the link https://youtu.be/1kqj7sWDslY for the clear solution to access the data base secretes from firebase latest version which shows up Database secrets are currently deprecated ans use a legacy Firebase token generator. Update your source code with the Firebase Admin SDK.

I hope this helps someone