firebase / firebase-android-sdk

Firebase Android SDK
https://firebase.google.com
Apache License 2.0
2.27k stars 575 forks source link

Messages Still Received on Deleted Firebase Messaging Token #5824

Closed TarekkMA closed 5 months ago

TarekkMA commented 6 months ago

Environment Details

Problem Description

Original Issue reported here: https://github.com/firebase/flutterfire/issues/12567

Issue Summary:

Messages are still received on a topic even after the Firebase Messaging token, which had subscribed to the topic, is invalidated and a new token is generated.

Steps to Reproduce:

  1. Subscribe to a topic named test_topic.
  2. Send a message to test_topic and confirm it's received.
  3. Invalidate the current Firebase Messaging token:
    • Invoke deleteToken()
    • Then, request a new token with getToken()
  4. Verify that the new token is different from the previous one.
  5. Attempt to send another message to test_topic. Notice that the message is still received, despite the fact that the token which had subscribed to it has been deleted.
  6. Wait approximately 15 minutes and repeat sending a message to test_topic. The issue persists, indicating that messages are still delivered to a token that should no longer be subscribed to the topic.
argzdev commented 6 months ago

Hi @TarekkMA, thanks for reaching out. This is working as intended. The invalidated tokens aren't immediately deleted. Our internal jobs run on a daily basis and thus the deletion and invalidation of FCM tokens should be done in a day or so.

Update: The best course of action would be to just subscribe and unsubscribe to topics as needed. Take note that both subscribe and unsubscribe calls are done in the background, and there are no hooks that allows the SDK to detect when the subscribe/unsubscribe call completes, so there's also no guarantee how long the call may take, but I think it'll be a lot shorter compared to the 1 day duration.

Let me know if this answers your question. Thanks!

TarekkMA commented 6 months ago

Hi @argzdev, thank you for the information.

sumittiware commented 6 months ago

Hi @argzdev so, if we get the new token using getToken() after calling deleteToken(), the new token will be automatically subscribed to the older topics?

princebansal commented 6 months ago

Hi @TarekkMA @argzdev. The original issue mentioned here https://github.com/firebase/flutterfire/issues/12567 is different from the one that is being discussed here.

According to the original issue, the new token generated after deleting the old token is preemptively subscribed to the topics the old token was subscribed to. Here's an example of the observed behaviour with timeline: --- T(x) is time, N(x) is token, TP(x) is topic T0: Token generated -> N1 T1 N1 is manually subscribed to TP1 and TP2 T2 N1 deleted T3 Token generated -> N2 T4 N2 is automatically subscribed to TP1 and TP2

The last step at T4 is the real problem.

* How this affects our business use case? When the user logs out of the app, we delete the logged in user's token and allow user to log in anonymously and immediately generate a new token for the anonymous user. But since the new token is already subscribed to the topics that the logged user was subscribed to, it sends all the logged in user's notifications to the anonymous user. This results in a huge security* issue, because we send sensitive information in the notifications too.

argzdev commented 6 months ago

@sumittiware I've tested this now and this behavior is what's happening. However, I'm not sure if this is an intended behavior. I agree though, I believe resubscribing to the topic should be done, instead of it automatically subscribing to the older topic as mentioned in best practice from our documentations. I'll ask our engineer regarding this behavior.

Thanks for explaining this further, @princebansal. Although, I'm wondering is there any reason why we don't use unsubscribe to the topics? I think in your use case, you should be able to resolve this issue by unsubscribing the user whenever they log out.

Let me know if this helps. Thanks!

princebansal commented 6 months ago

@argzdev Thanks for the quick response. Unsubscribing wont be possible because we have no stored information of the topics that the new token is subscribed to. We store token to subscribed topic data in our database and use that data to subscribe or unsubscribe a topic from a token. But since this new token is freshly generated, ideally our system has no stored topics against it. Hence we wont know which topics we should unsubscribe from.

In ideal scenario, the freshly generated token should come with no topics subscribed, and we should be given the control to manage topics for that token.

argzdev commented 6 months ago

Sorry, I didn't clarify it further. You're correct calling unsubscribeFromTopic to the newly generated token would not really do anything. But what I mean is to call this for the old token before you generate a new token, would it not be possible to call the unsubscribeFromTopic?

In ideal scenario, the freshly generated token should come with no topics subscribed, and we should be given the control to manage topics for that token.

But yeah, I'm also under the impression that that's what's expected from the newly generated token. In the meantime, I've notified our engineers of this issue with internally tracking bug b/333061151. I'll keep you folks posted once I receive an update.

princebansal commented 6 months ago

@argzdev That sounds a great workaround actually but there's a small catch. Our logout flow is a pure client side operation, where we just clear the auth token stored in the app and allow the user to log in anonymously by hitting the server. And I think that's how most of the systems that use JWT for authentication do.

We would need an app release where we have to introduce server intervention in logout. I would prefer to let the fcm do its job correctly.

Thanks again for the escalation, eagerly waiting for the updates on this.

princebansal commented 6 months ago

@argzdev Any updates on this?

princebansal commented 6 months ago

Hi @argzdev Waiting for revert on this

argzdev commented 6 months ago

Hey @princebansal, it seems like our engineers are still taking a look into it. It'll take sometime before we can provide an update with this. Unfortunately, I'm unable to provide a timeline on when this will be moved forward. If you require an urgent solution, you could try what we've talked about earlier (using unsubscribeFromTopic) as a temporary mitigation while our engineers are still conducting the investigation. I'll try to bump up the internal bug as much as I can to push it with priority.

princebansal commented 6 months ago

Sure @argzdev . Thanks for the update

google-oss-bot commented 6 months ago

Hey @TarekkMA. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

TarekkMA commented 6 months ago

Waiting for updates from @argzdev

lehcar09 commented 5 months ago

Hi @TarekkMA, thank you for your patience. We have received a response from our engineer and according to investigation this is working as intended. For context, each FCM registration token contains the FID to target devices for message delivery. When you delete the token (deleteToken), the FID is still the same.

i.e.
//Current token: dlrmE***:APA91bEH***
Firebase.messaging.deleteToken()

Firebase.messaging.token
//New Token: dlrmE***:APA91bFy***

This leads to the same subscription being associated. That said, we recommend deleting the FID when you delete the token. Thus, the Topics fanout to the old/deleted FID will not be delivered.

i.e.
//Current token: dlrmE***:APA91bEH***

Firebase.messaging.deleteToken()

FirebaseInstallations.getInstance().delete()

Firebase.messaging.token
//New Token: e4Mrm***:APA91bGy***

I'll go ahead and close this issue now. Let me know if there's any misunderstanding and/ or we need to reopen this issue for further investigation.

princebansal commented 5 months ago

@lehcar09 Thanks for probing into the issue and providing a detailed explanation of the behaviour.

The recommended steps should definitely go in the relevant docs because I believe that the deleteToken() method doesn't convey the fact that the FID will stay same.

Zachary625 commented 4 months ago

Hi @TarekkMA, thank you for your patience. We have received a response from our engineer and according to investigation this is working as intended. For context, each FCM registration token contains the FID to target devices for message delivery. When you delete the token (deleteToken), the FID is still the same.

i.e.
//Current token: dlrmE***:APA91bEH***
Firebase.messaging.deleteToken()

Firebase.messaging.token
//New Token: dlrmE***:APA91bFy***

This leads to the same subscription being associated. That said, we recommend deleting the FID when you delete the token. Thus, the Topics fanout to the old/deleted FID will not be delivered.

i.e.
//Current token: dlrmE***:APA91bEH***

Firebase.messaging.deleteToken()

FirebaseInstallations.getInstance().delete()

Firebase.messaging.token
//New Token: e4Mrm***:APA91bGy***

I'll go ahead and close this issue now. Let me know if there's any misunderstanding and/ or we need to reopen this issue for further investigation.

This also helped us as well, it would be nice to put this in official doc: https://firebase.google.com/docs/cloud-messaging/manage-tokens, this and the delay of actual token deletion are both quite important for production, thank you very much!