cachapa / firedart

A dart-native implementation of the Firebase Auth and Firestore SDKs
https://pub.dev/packages/firedart
Apache License 2.0
174 stars 62 forks source link

Recommended way to renew authentication token #35

Closed guyluz11 closed 4 years ago

guyluz11 commented 4 years ago

I think that after number of days the authentication token is invalid and it crashing my program when trying to send to firesore.

Is there recommended way to renew the authentication token when it is expired?.

cachapa commented 4 years ago

Firedart refreshes the token automatically if it's about to expire: https://github.com/cachapa/firedart/blob/master/lib/auth/token_provider.dart#L28

Firebase tokens actually have 1h expiry time, so if the you're seeing problems after a few days then it might be a different issue. You could try to pass VerboseClient in the FirebaseAuth instantiation arguments. It prints the sent and received messages to the terminal to help with debugging. Just make sure to turn it off in production, as that might be a security issue :-)

I'm closing this issue for now since the title could be misleading. We can continue discussion here and reopen if we identify a problem in the package.

guyluz11 commented 4 years ago

Could it be closed stream? "Closed streams are not automatically recovered." Is there recommended way to catch closed stream and reopen it?

cachapa commented 4 years ago

You can monitor the stream for onCompleted and onError events.

guyluz11 commented 4 years ago

Ok will try. By the way it looks like I didn't "pass along an instance of FirebaseAuth" so I was just guest user I guess

meteorza commented 4 years ago

guyluz11, did you manage to successfully restart the closed stream? Do you perhaps have a basic example of how to recover the closed stream?

I catch the gRPC Error (16, Missing or invalid authentication.) in the stream's onError and restart it, but it does not seem to receive any document snapshots after the restart. It receives the snapshots just fine before the error occurs.

guyluz11 commented 4 years ago

I didn't solved it, a new bug appeared that crash all the app so I am stuck on that.

cachapa commented 4 years ago

By the way it looks like I didn't "pass along an instance of FirebaseAuth" so I was just guest user I guess

Guest accounts also get an anonymous token, so you would still be subject to token renewal issues AFAIK.

Justus-M commented 1 year ago

You can monitor the stream for onCompleted and onError events.

I'm guessing onCompleted is onDone now? When does that come into play? Because ex. when I cancel the stream it doesn't seem to trigger onDone.

I managed to test onError by turning off the wifi on my computer. Is it enough to just create a new stream onError, or is there a better way to handle this, and are there other cases that flutterfire usually handles that I'd need to account for here?

cachapa commented 1 year ago

I meant to write onDone instead of onCompleted in my previous comment. Firedart uses standard Dart streams so the nomenclature is coming from there.

Dart streams do not emit onDone when canceled.

I don't recall if the stream is cancelled on error or not. This needs to be tested to check if the Firebase backend performs automatic recovery.

To be clear, Flutterfire is a wrapper around the Firebase protobuffs, so a lot of the actual functionality is not actually implemented by this package, but rather generated from the official Google definition.

Justus-M commented 1 year ago

Thanks @cachapa

Here is my solution

I get the following error when I turn off my wifi and wait 30-60 seconds

[flutter: Handling error gRPC Error (code: 2, codeName: UNKNOWN, message: HTTP/2 error: Connection error: Connection is being forcefully terminated. (errorCode: 10), details: null, rawResponse: null, trailers: {}) using FirestoreGateway._handleError

onError is called, but onDone is not. If I don't do anything, the stream indeed remains closed even when I turn my wifi back on.

However, if I do the following, the stream resumes when I re-connect to the internet.

Use a function to start/create the stream (let's call it startStream) that does the following:

  1. Create the stream with listen
  2. Assign a function to onError that recursively calls this function (startStream)

This way, whenever the stream fails, it will start a new one with the recursive call. If the internet is still disconnected, it will fail and try again (recursively/infinitely until it works).

something like this

Future<void> startStream() async {
    var collection = firestore.collection('myCollection');

    var subscription = collection.stream.listen((event) {
      print('do something');
    });

    subscription.onError((error) {
      startStream();
      return error;
    });
  }