I'm currently working on a web app which will allow a user to subscribe to push notifications. We'll store the subscriptions in a database table mapped against the user's ID and when a notification needs to be sent, we'll look up the user's subscriptions and send the notifications.
I've been following this guide:
https://developers.google.com/web/fundamentals/codelabs/push-notifications/
All is going well, but something just doesn't feel "right".
On every page load, the service worker is registered, then it checks if they're already subscribed, then even if they are it calls updateSubscriptionOnServer() which contains the following comment:
// TODO: Send subscription to application server
This effectively means that every page load is going to be attempting to write the same subscription back to the database. Obviously we'll handle that in the application, but it doesn't seem ideal.
With the Web Push API, is this the expected approach?
Many thanks
Yes it can be useful to send the subscription to server on every page load:
The user may have changed permission from blocked to granted (or default) in the browser settings, so you want to create the subscription and send it to the server
The subscription endpoint may change for different reasons, so you need to make sure that the current endpoint is sent to the server (the previous endpoint will return 410 Gone)
A compromise between the points above and performance can be to send the subscription to the server only on given pages (e.g. homepage).
Related
I'm managing authentication state in a readable store which is grouped with a promise that resolves when the auth state is known (either signed in or out). The store is set internally via onAuthStateChange.
I'm trying to access this auth state from the server (+layout.server.ts and +page.server.ts) so that I can redirect the user to a sign-in page if they aren't authenticated, or load data from the database if (and only if) they are. No matter what I try, whenever I access this store from the server, its value is always null. I think this is because Firebase is only supposed to run on the client, although I'm not sure. Is there any way I can access this store from the server, or change my implementation so that Firebase runs in the server and passes auth state to the client? This blog post explains pretty much exactly what I want to do, but the solution here seems more complicated than it needs to be.
I've tried moving Firebase initialization code to the server (in both hooks.server.ts and +layout.server.ts), but there's no way for me to pass the auth object to the client because it can't be serialized (I get an error explaining this when I try to return it from a load function in +page.server.ts). I've also tried to handle authentication only using client-side code, but the server is responsible for loading data from the database, so in this case there's no way for me to verify a valid authentication state from the server.
author of the blog post you linked here.
You are correct in that the firebase client is only supposed to run on the client. If you want to access the Firebase services server-side you're supposed to use Firebase admin.
In my post I'm working around these limitations that firebase sets and unfortunately you do need that much code.
You are forced to do all the authentication in the frontend (firebase-client) and only afterwards you can inform the backend of the user info. (through the cookie)
Before I wrote this the ideal solution I had in my head was this:
Send the user to a login page that lists all the possible login providers.
The user chooses one and logs in.
the user gets redirected to a callback page where we can do something with the auth data in the backend.
I do think that something like this flow is possible if you're using custom tokens. But I'm sure that will be a whole load of even more complicated code.
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.
I use Firebase Remote configuration to control my app features per user segment and so I apply conditions on remote configuration parameter based on some user properties.
The issue is that some of these user properties could be changed when the app user make some actions that change his/her segment (like user was free user and becomes a paid users) and in this case, Remote configuration doesn't fetch the new values so the user sees wrong data in the current app session (sees data related to his previous segment not the new one) and will not see the right data until he/she closes the app and opens it again.
-Are there any solution to force Remote Configuration to update the cached value?
-Is it right to use Remote Configuration in these case or we have to move to another solution like RTDB?
You can trigger Firebase reload by sending silent FCM message either to devices with specific property value or to all devices. Naturally you need to implement handling for the notification and reload triggering. This page describes the implementation very well.
I'm trying to create an app that uses push notifications. I have done all the work in both 3rd-party server and application development and the notifications are sent successfully.
In this certain part of the application, the user will be registering to GCM and 3rd-party server, through a specific service, and then uploading to the 3rd-party server the football games that he wants to be notified when they are completed.
The problem that I'm facing is that when I uninstall the app, the GCM servers (when I'm sending a message) don't respond with the NotConnected error. So when I re-install the app the GCMRegistrar gives me a new registration id and this makes my server to have two different registration ids for the same user.
Although I can solve this problem with the help of the canonical id. In particular Google says
"canonical_ids": 1
"results": [{ "message_id": "1:2342", "registration_id": "32" }]
success, but the registration ID should be updated in the server database (from 23 to 32)
So if I listen to google's advice, with changing the registration id to the older (working) one, this will cause afterwords the application, with the new registration id, to send the football games to the server with this specific new registration id and the server will not understand where to store this info.
I know that a registration id is not a user's id but a registered device's id.
My first thought is to let the server have different registration ids. So when I get a canonical id, I will ignore it. I don't like this idea though...
My second thought is when I change the registration id to the older one, to update it somehow into the app...
Can anybody tell me which sounds better to my situation? This is the first time that I use push notifications...
So if I listen to google's advice, with changing the registration id to the older (working) one
That's the opposite of what Google tell you to do. They encourage you to remove the old ID from your DB and keep only the new registration ID.
Here's the relevant quote :
Canonical IDs
On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.
GCM provides a facility called "canonical registration IDs" to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your application. This is the ID that the server should use when sending messages to the device.
If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the registration_id field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.
I'm working on a push architecture that needs to support applications which allow for multiple users. This means more than one user can log into the application with their credentials. The problem I'm running into is what if user A allows push notifications, then logs out, then user B logs in and starts getting user A's push notifications?
What are some best practices for handling this type of thing? One thought I had was you could remember the last user who logged in and only display push notifications to the "logged in" user. You would have to send some sort of user context in the message payload so it could be checked against the logged in user. However this feels a little funky.
Anyone else ran into this? It's seems like a really relevant problem, especially for tablets where families tend to share the device.
We're implementing this by Registering the device with APSN, getting the device token and sending this to our server through a ws.
On the server side the device token is only associated with the last logged in user.
New app
User A (first ever user) uses IPAD A
Register with APSN, get token
Send token to our servers through ws
Search for token in db, token is new, store it
assign token to USER A
Next user logs into app
Register with APSN, get token
Send token to our servers through ws
Search for token in db, token exists already
Remove connection to USER A
assign token to USER B
SEND Notification to device WITH USERNAME
if username is logged in show it - else dont
Still not perfect as its sent to home screen first so to ALL users
I think your suggestion is acceptable in a multi-user app. It is much simpler to implement this in the client side, than on the server side. The downside is extra bandwidth wasted to send an unneeded notification. But vast majority of the usage is probably single-user so this may not matter much.
The alternative is to track the logged on users on your server and their current reg_ids. This could be more complicated because A could be logged on on multiple devices, then logs out from device 1, and B logs onto device 1, etc. and your server has to track all of these. So probably another table to track the relationships between 'Logged On Users' to 'Reg Ids'.
If you hate the idea of sending unneeded notifications, go with the server route. If you value Keep-It-Simple principle, go with the client route.
Let's suppose users of your app can logging on multi devices.
We have to make two API on server side:
func setUserDeviceNotifyToken(userId: Int, deviceToken: String) {}
func removeUserDeviceNotifyToken(userId: Int, deviceToken: String {}
On your app side, you have to call setUserDeviceNotifyToken API on every Login In and call removeUserDeviceNotifyToken on every logout.
On server side, you can track every user with its deviceNotificationToken and send notification for correct device.
Notice: If your service doesn't suppose to support multi device login with one user, you can handle it just by one updateUserDeviceNotifyToken and pass null for remove user's device token.
Notice 2: Do not let user logout before calling removeUserDeviceNotifyToken API.