AsifArmanRahman / firebase-rest-api

A simple python wrapper for Google's Firebase REST API's.
https://firebase-rest-api.readthedocs.io
MIT License
60 stars 14 forks source link

[Bug]: Firebase Realtime Database stream fails when token expires #25

Open dwatrous opened 1 year ago

dwatrous commented 1 year ago

Is there an existing issue for this?

Environment

-   OS: Windows/Linux
-   Python: 3.10.7

What happened?

When the idtoken expires, I'm required to kill my script and open a start it again to get a new token and create a new stream.

Code Snippet

When I create a stream, I provide it a valid idtoken. This token expires within an hour and needs to be refreshed. Right now my script is failing when this idtoken expires. Here is what I'm doing to create the stream

`self.my_stream = self.db.child("messages").stream(self.message_capture, token=self.idtoken)`

`self.idtoken` is defined in a way that it would always return a fresh token, but I noticed that URL caches the value of the token when the stream is created (https://github.com/AsifArmanRahman/firebase-rest-api/blob/cf2772a6549d47d6d5ee6750e9bb77f5f9c4f679/firebase/database/__init__.py#L583). This means that the stream can only ever live as long as the token it is given.

In the `Stream` class, I see that there is an instance of `KeepAuthSession` that is used to create the `ClosableSSEClient`, but this doesn't appear to be complete, or at least I can't figure out if this is supposed to be a way to refresh the token. It looks different.

Relevant log output

2023-11-08 10:27:36,303 DEBUG _new_conn(973) Starting new HTTPS connection (2): mosquitomax-364012-default-rtdb.firebaseio.com:443
2023-11-08 10:27:37,136 DEBUG _make_request(452) https://mosquitomax-364012-default-rtdb.firebaseio.com:443 "GET /messages.json?auth=eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ0OWU0N2ZiZGQ0ZWUyNDE0Nzk2ZDhlMDhjZWY2YjU1ZDA3MDRlNGQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbW9zcXVpdG9tYXgtMzY0MDEyIiwiYXVkIjoibW9zcXVpdG9tYXgtMzY0MDEyIiwiYXV0aF90aW1lIjoxNjk5NDU3MjU2LCJ1c2VyX2lkIjoiakxFMk9yUzI0TmVObkFHcXdHMTM5QWZlb0pQMiIsInN1YiI6ImpMRTJPclMyNE5lTm5BR3F3RzEzOUFmZW9KUDIiLCJpYXQiOjE2OTk0NTcyNTYsImV4cCI6MTY5OTQ2MDg1NiwiZW1haWwiOiIwMDAwMDAwMGQyOWY5NmRmQG1vc3F1aXRvbWF4LmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyIwMDAwMDAwMGQyOWY5NmRmQG1vc3F1aXRvbWF4LmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.kIvcRCuG0TLu9MwiuR8lF7C7WOI1_jW37gMImoaiLWLyDzG216GKJiNwXvOr0thhTLRRESkQV9GeMiNAutyifZZhUGBG0TcqAx_mmwjENfvzF5NFltzSK6q1AHya1Q3X5xxty2oDCDpY7VZIZl6Z5TZ86y9R95vwTNWf4bbI7IQRsWVDeiioc_ZRRPQCqt4fGsSO0mUfLoQ5LfzdjKjvUJijQGILFlboWpOgjVHsCU9alHuXuRXOb0b5UNS7H1XJun8QQQvaj_BZu92uyCH1_xcrw01Mlw6kagGXX0W3Nw02MG-B3TFqX87lw4hOB-Jm3yIsWwAaC59V_otyhB7KNA HTTP/1.1" 401 21
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.9/threading.py", line 892, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_stream.py", line 48, in start_stream
    for msg in self.sse:
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_custom_sse_client.py", line 99, in __next__
    self._connect()
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_closable_sse_client.py", line 21, in _connect
    super(ClosableSSEClient, self)._connect()
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_custom_sse_client.py", line 67, in _connect
    self.resp.raise_for_status()
  File "/usr/local/lib/python3.9/dist-packages/requests/models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://mosquitomax-364012-default-rtdb.firebaseio.com/messages.json?auth=eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ0OWU0N2ZiZGQ0ZWUyNDE0Nzk2ZDhlMDhjZWY2YjU1ZDA3MDRlNGQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vbW9zcXVpdG9tYXgtMzY0MDEyIiwiYXVkIjoibW9zcXVpdG9tYXgtMzY0MDEyIiwiYXV0aF90aW1lIjoxNjk5NDU3MjU2LCJ1c2VyX2lkIjoiakxFMk9yUzI0TmVObkFHcXdHMTM5QWZlb0pQMiIsInN1YiI6ImpMRTJPclMyNE5lTm5BR3F3RzEzOUFmZW9KUDIiLCJpYXQiOjE2OTk0NTcyNTYsImV4cCI6MTY5OTQ2MDg1NiwiZW1haWwiOiIwMDAwMDAwMGQyOWY5NmRmQG1vc3F1aXRvbWF4LmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyIwMDAwMDAwMGQyOWY5NmRmQG1vc3F1aXRvbWF4LmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.kIvcRCuG0TLu9MwiuR8lF7C7WOI1_jW37gMImoaiLWLyDzG216GKJiNwXvOr0thhTLRRESkQV9GeMiNAutyifZZhUGBG0TcqAx_mmwjENfvzF5NFltzSK6q1AHya1Q3X5xxty2oDCDpY7VZIZl6Z5TZ86y9R95vwTNWf4bbI7IQRsWVDeiioc_ZRRPQCqt4fGsSO0mUfLoQ5LfzdjKjvUJijQGILFlboWpOgjVHsCU9alHuXuRXOb0b5UNS7H1XJun8QQQvaj_BZu92uyCH1_xcrw01Mlw6kagGXX0W3Nw02MG-B3TFqX87lw4hOB-Jm3yIsWwAaC59V_otyhB7KNA

Anything else?

2023-11-08 10:27:36,303 DEBUG _new_conn(973) Starting new HTTPS connection (2): myproject-rtdb.firebaseio.com:443
2023-11-08 10:27:37,136 DEBUG _make_request(452) https://myproject-rtdb.firebaseio.com:443 "GET /messages.json?auth=IDTOKEN HTTP/1.1" 401 21
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.9/threading.py", line 892, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_stream.py", line 48, in start_stream
    for msg in self.sse:
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_custom_sse_client.py", line 99, in __next__
    self._connect()
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_closable_sse_client.py", line 21, in _connect
    super(ClosableSSEClient, self)._connect()
  File "/usr/local/lib/python3.9/dist-packages/firebase/database/_custom_sse_client.py", line 67, in _connect
    self.resp.raise_for_status()
  File "/usr/local/lib/python3.9/dist-packages/requests/models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://myproject-rtdb.firebaseio.com/messages.json?auth=IDTOKEN
AsifArmanRahman commented 11 months ago

or at least I can't figure out if this is supposed to be a way to refresh the token

Unfortunately, I'm not sure either. That part of the code was taken from Pyrebase.

dwatrous commented 11 months ago

I ended up moving to https://github.com/JelleZijlstra/aiohttp-sse-client2. That still doesn't support automatic refresh of the token, so I run in a loop that watches for the SSE "auth_revoked" and then I get a fresh token and start a new listener.

AsifArmanRahman commented 11 months ago

Maybe in future me or someone from the open source will figure it out. Until then, I'm glad you found a work through for your project and mentioning it here for future solution seekers.