7

First of all, I've already check these questions, without any luck:

I am trying to implement web push notifications for a web app that I'm working on. Currently, I've achieved the following goals:

  • Create a VAPID keys pair (with this guide).
  • Register a service worker (only a service worker, I think that manifest.json is no longer required).
  • Subscribe the user to the server (subscription data will be stored in the database).
  • Send a push notification with webpush gem.

After setting it up, everything works fine (on localhost and on a remote machine). However, after some hours (between 12 and 24 hours), the notifications stop working on the remote machine (localhost works perfectly). After that time, the following errors are thrown when sending the push notifications from the server side (Rails):

  • Chrome: UnauthorizedRegistration 400 (no extra info).
  • Firefox: {"code": 401, "errno": 109, "error": "Unauthorized", "more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes", "message": "Request did not validate Invalid bearer token: Auth > 24 hours in the future"}

After this error appeared, I tried to unsubscribe and resubscribe the user on every page visit. The subscription field on the db is updated after the resubscription is done, but the error is still being thrown, with the same information. No errors are thrown on the browser, nor service worker.

I've tried to force the resubscription manually by placing some js code on the Chrome Dev Tools console, unregistering the service worker, and reseting the push notification permissions, but nothing solves the error. I can only fix this error by creating a new VAPID key pair rebooting the remote machine. After crebooting the machine, I've another 12-24 hours before it fails again. Also, the notifications send process don't work neither on rails server (nginx + unicorn), rails console, nor irb.

I don't know where to go from now. Even worst, I can only try fixes once a day, since it'll break every 24 hours. I think I need some external help with a fresh vision of the problem. Am I missing something? Is there any OS dependency that VAPID uses and needs to be restarted?


Here are some code snippets that may be useful. Sorry for the mess, but I've done tons of modifications to try making it work.

Service worker registration:

serviceWorkerRegistration = null registerServiceWorker = -> if 'serviceWorker' of navigator && 'PushManager' of window navigator.serviceWorker.register("<js url>").then (reg) -> serviceWorkerRegistration = reg checkSubscription() .catch (error) -> console.warn 'Service Worker Error', error else console.warn 'Push messaging is not supported' registerServiceWorker() 

User subscription and resubscription

# Refresh user subscription (unsub + sub) refreshUserSubscription = -> unsubscribeUser(subscribeUser) # Subscribe the user to the push server subscribeUser = -> return if !serviceWorkerRegistration # Subscribe serviceWorkerRegistration.pushManager.subscribe userVisibleOnly: true applicationServerKey: urlB64ToUint8Array('...') .then (subscription) -> pushSubscription subscription .catch (err) -> console.warn 'Failed to subscribe the user: ', err # Unsubscribe user unsubscribeUser = (callback)-> return unless serviceWorkerRegistration serviceWorkerRegistration.pushManager.getSubscription().then (subscription) -> if subscription subscription.unsubscribe().then(callback) else callback() .catch (error) -> console.warn 'Error unsubscribing', error # Push subscription to the web app pushSubscription = (subscription) -> data = if subscription then subscription.toJSON() else {} $.post "<back-end endpoint>", subscription: data # Fetch current subscription, and push it. checkSubscription = () -> serviceWorkerRegistration.pushManager.getSubscription() .then (subscription) -> pushSubscription(subscription) # I think that this should be done with promises instead of a simple timeout. setTimeout refreshUserSubscription, 1000 

Service worker:

self.addEventListener 'push', (event) -> title = "Example" options = { body: "Example" } notificationPromise = self.registration.showNotification(title, options) event.waitUntil(notificationPromise) 

Web push call:

webpush = WebPush.new({ endpoint: '...', keys: { p256dh: '...', auth: '...' } }) webpush.set_vapid_details( "mailto:#{CONTACT_EMAIL}", "<base64 public key>", "<base64 private key>" ) webpush.send_notification("foo") 

2 Answers 2

1

After changing the expiration time from 24 hours (default) to 12 hours, it now works properly:

Webpush.payload_send( message: "Hi!", endpoint: "...", p256dh: "...", auth: "...", vapid: { subject: "...", public_key: ENV['VAPID_PUBLIC_KEY'], private_key: ENV['VAPID_PRIVATE_KEY'], exp: 12.hours } ) 
Sign up to request clarification or add additional context in comments.

1 Comment

hi, I'm trying to implement a similar thing (stackoverflow.com/questions/50361320/…). one point I can't understand is if I have to refresh the browser subscription registration, or once the browser allows notifications and sends the subscription, that's all is needed to send notifications indefinitely? I'm getting 401 NotRegistered after 24 hrs or so
1

It looks like the library has changed, this is how I fixed it:

def send_push(payload, endpoint, p256dh, auth) Webpush.payload_send( message: payload, endpoint: endpoint, p256dh: p256dh, auth: auth, vapid: { public_key: '...', private_key: '...', expiration: 12 * 60 * 60 } ) end 

Notice the key is expiration not exp and it's the expire time in seconds.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.