Swift - FireStore/FCM (Firebase Cloud Messaging) - firebase

I've incorporated Firebase Cloud Messaging into my app. After messing around, I kind of understood the premise of how it operates. So, as a result, I structured my code so that when users sign up the FCM token is stored. After creating two accounts, I realise both FCM tokens for the user were the same.
Looked online and sorted this issue, and now I can refresh the token on launch, and still append the new FCM token when users initially sign up.
So now, I ask the question - Users are created with a fcmToken field (which I can refer to in my code), however, due to the fact a new token is generated on launch each time does this render the token(s) stored for each user useless? Or can I still push to the specific user using the fcmToken?
I've looked online, but can't seem to find an answer.

FCM tokens don't uniquely identify an individual end user. They identify a specific installation of an app on a specific device. When sending with that token, it doesn't matter who is signed in to the app (or if anyone is signed in at all) - the app will still receive it and need to figure out what to do with it. It's up to you to decide what to do with that message, given the sign-in state of the user. If you expect that your app could have multiple users sharing a single app on a single device, then you will probably want to send something in the payload to determine who that message was intended for, if necessary.

#doug great answer, but there's a common implementation problem when people share a device, so please add a warning, something like: often only the last logged in user should receive push notifications, otherwise he could see messages from the person who was logged in before. your backend should not only store all the devices a user is logged in, but also for each device who the last active user is and check this upon sending a push. the question whether you receive push or not when logged out is a common topic, too.

Related

Firebase database call working even when Authenticated user is disabled

I use Firebase Firestore and Firebase Authentication in my project.
I am testing out what would happen if I go into firebase console and manually click the "Disable account".
I would expect that if the account is suspended, the authenticated user (test#mail.com in this case) will immediately receive error whenever a Firestore database is called (eg. getDocs(q) or setDoc()). The reason behind this assumption is that I assume Firestore tries to authenticate each call before doing CRUD.
However, after testing out, here is the test and result
Login user (test#mail.com)
Do a db read or write ensure everything works which it does
Go to firebase console and disable the account (test#mail.com).
Try to do another db read or write. The result here is that I was able to still read and write which is not what I expected.
So here are my questions
Is this a normal behavior?
Can I write Firebase security rule to overcome this issue?
It would be less idea if I have to check if user is logged in everytime I do a firestore call. But if that is what I have to do, how can I do that. I believe getAuth()and onAuthStateChanged is not really suitable in this case. Reason being getAuth() seems to only check the database the first time it is called. Any subsequence call it only checks the app memory and do not perform any network request at all (Verified by looking into console network tab). Which is kinda weird. And onAuthStateChanged does not listen to firebase state change, it only listens to if my app logs a user in or out.
Abit of background on what I am trying to achieve
I want to be able to lock a user out from my app by changing something from the db. And ideally not having to PING every few second .
Update:
It seems like it takes about 1-2 hour for my app to automatically recognise that the account has been disabled. It took takes alot longer than what I anticipated. I would still like to know if there is a better solution rather than wait though.
Firebase Authentication works with a combination of long-lived refresh tokens and short-lived ID tokens. The latter tokens are valid for one hour from the moment they are minted, and cannot be made invalid after they are minted.
So it may take up to an hour before your client gets a new token, and detects that its account has been disabled. You can force the client to update its ID token at any time by calling getIDToken(true). This will ensure the client has an updated ID token, but it won't invalidate the older ID token (since it's impossible to invalidate a bearer token).
What you'll want to do is write the UID or ID token to your database when you disable the user account, and then check for that in your security rules.
Also see the Firebase documentation on detecting token revocation.

Is there any way to figure out the user is already login in any device Firebase Auth

Is there any way to get to know the a user is already logged in any other devices ?.
In Firebase Auth service.
Anyone please let me know is there any predefined provision in Firebase Auth.
UserMetaData has the last sign in time. You can also set auth state persistence to be either local, session, or none.
You could use these to approximate whether a given user could be authenticated elsewhere, but it doesn't seem like there's data on whether a user is definitely currently authenticated somewhere. For that you'd need to store login/logout data separately, such as in a a Firestore document for each user.
Note that the auth service doesn't typically know (or care) whether the user is actively using the app... it just issues each user an authentication token, which is used over some period of time to prove that they are who they say the are. The token can be invalidated/refreshed from time to time for security reasons (according to the persistence setting), but it's not an indication of whether they're "active". You don't mention your use case, but if you're trying to figure out whether users are on or offline (say for a chat application), you should look at Firebase's offline capabilities.

When and what Old FCM Tokens do I need to delete from my backend?

The way I understand Firebase Cloud Messaging at the moment, I will want to save all FCM tokens a user might have across devices to my backend and send a notification to all of these tokens at once when I want to notify that user about something.
Multiple tokens
Until this point, I assumed that each device only has one active token, however, reading this section of the documentation:
To enable this feature, make sure you have each sender's sender ID. When requesting registration, the client app fetches the token multiple times, each time with a different sender ID in audience field, using the token retrieval method for the given platform
Does this mean that I might need to target multiple active tokens per device?
Deletion
And now coming to the really important question. A simple solution to the above problem would be to simply store every token I ever retrieve in the backend and thus ensuring that my user will always receive the message.
However, what do I do if the user signs out of my app using Firebase Authentication, i.e. a different account is used in the same app on the same device?
I assume that the tokens I sent to my backend for this device will still be active - so now this user will receive notifications from another account because that account was signed in on the device previously.
I do have access to the current FCM token and I could delete that from my backend before signing out the old user, but considering the "Multiple tokens" section: how do I make sure that I can delete all FCM tokens of the old user from my backend?
Uniqueness
Additionally, assuming that old tokens are just dead for the device (will not trigger notifications anymore) when new ones are generated, can I be sure that this token will never be assigned to another device in the future?
TL;DR
How can I make sure that I have the correct FCM token(s) for my user stored in my backend and more importantly: how can I ensure that no tokens of other users are saved for some user in my backend?
I read through:
https://stackoverflow.com/a/40158260/6509751
However, I still do not know how to deal with multiple tokens.
Does this mean that I might need to target multiple active tokens per device?
An application has a single active token for each sender ID. It's fairly uncommon to have multiple sender ID, and you'd usually know if if you do. If you're sending from a single back-end, there's usually no need for having multiple sender IDs.

Are Firebase Cloud Messaging (FCM) tokens unique?

I can't find any place in firebase docs, where indicated that received tokens are unique. I will be grateful if someone could point me such place. Main question - should I make unique constraint in database for such tokens. Thx!
According to documentations, they're unique, but you can't bind them to a specific device since they might change.
Documentation for IOS:
The registration token may change when:
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
Documentation for Android:
The registration token may change when:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
When I search for Are Google Cloud Messaging tokens unique, the first result is this page from the documentation, which says:
To verify that they can send and receive messages, client apps must register with GCM. In this process, the client obtains a unique registration token...
Firebase Cloud Messaging Instance ID Tokens uniquely identify an instance of an app. They are globally unique.
Whether you should mark the column in your database as unique depends on your usage of that column. As yourself questions like: what bad thing will happen if a token is present twice in this table? Will marking the column unique prevent the bad thing from happening?
As per my experience I have noticed that the FCM token is changed in three scenario they are as follows:-
When the application is uninstalled or reinstalled.
When the data of the application is cleared.
When the application is installed in new device.
Note:- There is no way to keep the FCM token same.
Yes, they are unique but they are not constant. Means for first time when I had installed one application then FCM token was let's say abcd but when I uninstalled the app and again installed the same app then my FCM token was not abcd but something else.
So, FCM tokens are unique but they are not constant, they keep on changing when we uninstall and install the application.

Firebase Cloud Messaging for Web - How to maintain the token list in the database and ensure they are valid or up-to-date

With Firebase Cloud Messaging for Web,
How do I maintain the list of valid tokens in my database? For example I've noticed when a user turns off notifications and revisits the site, a new token will be generated and the old token in my database is useless.
I've also tried using Firebase messaging.onTokenRefresh() callback, but it does not get called when I turned off notifications. Also in this case, even if it did get triggered, it returns a new token that was refreshed. How do I keep track of the old token that was refreshed?
Can someone please share with me their thoughts/ways to maintain and ensure the token list in the database are valid or up-to-date?
Any feedback is much appreciated.
Thank you,
Christina
messaging.onTokenRefresh() is probably a wrapper around the event onpushsubscriptionchange.
Indeed that event is currently only called when the subscription is enabled (or enabled again), but not when the permission for push notifications is revoked. So at the moment you can only know that an endpoint has expired when you try to send a notification to it.
More details:
http://blog.pushpad.xyz/2016/05/the-push-api-and-its-wild-unsubscription-mechanism/
In any case you can use the callback to send any new token to the server: at first you will have two tokens stored for the same browser, one expired and the other valid.
Some problems arise if you have data associated to the endpoint (e.g. tag) that you want to preserve during the endpoint change: see the blog post for some suggestions.

Resources