Get device token with react native - push-notification

Is there any way to get the device token for notifications on demand with react native? It seems, from the docs, like the only time the token is exposed is on the PushNotification register event.
More generally, what's the common practice for handling device tokens?
If one user logs into my app, the app requests permissions from PushNotification, the register event is fired and I can associate that device with the logged in user. So far so good, but if that user logs out, and I break that association to stop the notifications, what do I do when another user logs in? The app already has permissions, so register won't fire again. How do I get the device token to associate it with the new user?
Or am I thinking about this the wrong way?

It seems my assumption that the register event only fires when the user grants access was the problem. The register event will fire in response to a call to requestPermissions whether or not the user was prompted. So by requesting permissions and responding to the register event when the app loads, you can always get the device id. Like so:
PushNotificationIOS.addEventListener('register', (token) => {
... store or use the token here ...
});
PushNotificationIOS.requestPermissions();

Related

how t check if notifications are allowed with FCM without triggering a permission prompt

I want to know if the user has allowed notifications on the current browser so I can show that state on the UI, but I don't want to trigger the request permission unless the user performs an action to enable notifications.
This is kind of a chicken egg problem because I don't have a reliable way to identify the current user browser.
I can store the FCM token on the firebase database and fetch it on the FE. But each token is unique for each browser and I can not compare it to anything, the only way I have to check if one of the existing tokens is for the current browser is to use the getToken method from firebase FCM and check the returned token is on the list of tokens, but that may trigger a request permission prompt and I don't want that unless the user asks for it.
One possible solution may involve storing a flag on local storage, but if the user clears it the UI will show notifications as disabled when the user is still subscribed to the FCM topic. I know the Notification API has a property that indicates if the user has granted notification permissions but that may have happened and the token not retrieved for some random network error, so I can not rely on this solely. Also it only indicates if the user has granted permissions, but on my application logic notifications may be disabled (because user choice) and that does not revokes the permissions.
Things are also not nice if user wants to disable notifications: in order to delete the token from the database, I need the current browser token, and the only reliable way to know the current browser token is to ask it with getToken which may trigger a request permission if the user has disabled notifications and I will never get the actual token and I need it to remove it from the database
Are there any guidelines about how to deal with this? The FCM docs are quite sparse
This is a solution that I'm not sure if it is super robust, but it's simple and probably to meet most cases.
First, check if the current browser has notifications allowed. If not, just show that value on the UI because the user will not get the notifications anyway even if they are subscribed on the backend side.
If notifications are already allowed you can safely run getToken (will not trigger permission request) and compare the value against the values on the user/profile database.
Because I'm using react here is an implementation on a hook:
const areNotificationsAllowed =
Notification && Notification.permission === "granted";
useEffect(() => {
// because we don't want to trigger a permission request
if (!areNotificationsAllowed) return;
// Notifications are allowed, we can safely run getToken to see if they are activated on this browser
messaging.getToken({ vapidKey }).then((token?: string) => {
if (!token) return setNotificationsEnabled(false);
if (notificationsCfg[token]) setNotificationsEnabled(true);
});
}, [areNotificationsAllowed])

Firebase Auth subscription

I'm working on a app which uses Firebase Auth to signup and login, but I'm facing some things which I don't know how to start. Users need to registrate on a website and they need to pay a subscription before the user is created in firebase, when they don't pay anymore, the user account should be disabled. So basically, users registrate on the web and after they pay, they can log into the app with their credentials.
Edit:
Since yesterday I'm trying to implement either mollie or stripe, but I can't get myself started, online there are very few video's about payments in combination with firebase
There are basically two ways off the top of my headto do this:
A) Secure but it involves cloud function and creating custom authentication token to login.
User registers with email.
User keys in login information and posts to cloud function.
Find user's uid/email and check for password.
Fetch the subscription document and check if it is active.
If it is inactive, return an error message accordingly.
If it is active, create an authentication token and return to user to login.
B) Client side checking, less secure but will do the trick.
User logins
Fetch subscription using user's uid. Check its validity
Force redirect user to subscription page if it is inactive with
error message. OR Autologout user if it is inactive with error message.
May I also suggest Stripe for their subscription service (Not sponsored)? Unless you already have an implementation in place.

STOP Push notification after logout

I'm using angular in my project which user swPush. The notification works fine, but even after user1 logged out am getting the push notification. I don't want to push notification to the logged out users.After the user2 logged in both user1 and user2 getting notifications on the same device, this confuses the user. I want to restrict the user to get notification only when they logged in. How can I do achieve this. Is there any method.
I already try unregistering the service workers using
navigator.serviceWorker.getRegistrations().then(function(registrations) {
for(let registration of registrations) {
registration.unregister()
}
})
But after using this, both the users are not getting notification.
Thanks and regards
You should not unregister the Service Worker registrations because, well, that unregisters all of them. Unregistering Service Worker prevents any push logic from happening since web push is a layer on top of Service Workers - you need to have Service Workers registered and active in order to use push notifications, right?
You have two options if you only think about "showing the notifications":
When the user logs out, stop sending the push notifications. Of course this means that the web app logic has to inform your server somehow that now the logout event happened and precisely who it was (which of the possible different browser sessions of this particular user). Of course your server should already have information about the logout event.
Keep track of the logged in user in the browser (your JS code) and only show push notifications relevant to that user. You need to somehow distinquish between the receivers of the push notifications and the active user sessions in the browser and most likely handle it in self.addEventlistener('push', ...) in the SW.
If you think about privacy/security standpoint, the option #2 is of course wrong. If you only hide/not show the logged-out user's notifications, it means you're still sending them from the server. The notifications could include private information and whatnot.
So really you should go for #1. That's the right way to implement this. It leaks no information from the logged-out users, keeps the users' push subscriptions separate, and saves bandwidth.

Deleting user from Admin API does not trigger .onAuthStateChanged in client

I am deleting a user from a firebase cloud function.
admin.auth().deleteUser(user_uid)
However, I was expecting that the following client side listener would trigger:
firebase.auth().onAuthStateChanged(() => // do stuff)
That is to say, the users deletion would also change his/her auth state from signedIn to signedOut.
The cloud-function call executes correctly, however the user is still logged in. Do I also have to log them out? (I see no admin .logOut method available.
I was thinking that after the successful Function execution I would then programmatically log them out from the client side.
Am I missing something?
EDIT: Deleting the user from the client side does trigger .onAuthStateChanged, so from the client side it does change his/ her auth state.
That's not the way auth state listeners work on the client. Those listeners trigger when the state changes from the perspective of the client. It doesn't know of changes that happen immediately on the server, at least not until the client tries to refresh its auth token. It's not "realtime" in connection with the server like Realtime Database.
If you want to wire up your own client notifications for user deletion, you could have the client listen to a per-user location in Realtime Database, and use the changes there to know when the user has been deleted.

About Firebase auth returned object

I have a react native app that users can login or signup through it, I use firebase to log them in but I don't understand what am I supposed to do with the returned object from firebase.auth().signInWithEmailAndPassword(email, pass); and createUserWithEmailAndPassword(email, pass);.
Am I supposed to use one of the parameters it returns? how?
Is each backend call (my backend not firebase's) supposed to be with one of the strings it returns?
Also which strings should I save on local storage so the users won't have to login again? I set firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);.
Also which strings should I save on local storage so the users won't have to login again? I set firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);
This ensures that Firebase persists the authentication token in local storage. You don't need to do anything else. When the app restarts, Firebase automatically finds the token in local storage and re-authenticates the user with that information.
Most likely you will need to add a listener to onAuthStateChanged() to ensure you can update the UI of your app to this authentication state. For more on this see getting the current user in the Firebase documentation.
In the case of a SPA (Single Page application), the returned object from firebase.auth().signInWithEmailAndPassword(email, pass); should be used to set the user name, email fields and display photographs inside your protected app pages. Also, since the user is in signed in state you can display private links inside this promise. You can also update user's profile inside this promise.
In the case of a multi page application, you might check the profile verification status and then redirect to your app's home page on the basis of the same.
You are supposed to get the ID token in your backend to identify valid requests
Firebase automatically stores the current user data in local storage which persists till the user logs out or the localStorage gets corrupted(?). You can confirm this from the fact that firebase auth does not work in case of Safari private browsing mode as it doesn't support localStorage methods.
In short, nothing has to be done on your part to ensure data persists in localStorage, Firebase uses onAuthStaeChanged event listener to toggle sign in stage for a given user across all registered devices.

Resources