Web Push with VAPID: 400/401 Unauthorized Registration

First of all, I have already checked these questions with no luck:

I am trying to implement web push notifications for a web application that I am working on. Currently I have achieved the following goals:

  • Create a VAPID key pair ( with this tutorial ).
  • Register a service worker (only a service worker, I guess manifest.json

    not needed anymore).
  • Subscribe the user to the server (the subscription data will be saved in the database).
  • Send push notification with webpush gem.

After setup everything works fine (on localhost and on remote machine). However, after a few hours (12 to 24 hours) the notifications stop working on the remote machine (localhost works fine). After this time, when sending push notifications from the server side (Rails), the following errors occur:

  • Chrome: UnauthorizedRegistration 400

    (no more 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 getting this error, I tried to unsubscribe and redirect the user on every visit to the page. The db subscription field is updated after the re-subscription is complete, but the error is still being thrown with the same information. Errors do not occur in the browser and are not serviced by the service.

I tried to force the re-subscription by putting some js code in the Chrome Dev Tools console, unregistering the service worker and restarting the push notification permissions, but nothing solves the problem. I can only fix this error by creating a new VAPID key pair by restarting the remote computer . After painting the car, I still have 12-24 hours before it fails again. Also, the process of sending notifications does not work on either rails server (nginx + unicorn), rails console, or irb.

I don't know where to start. Even in the worst case, I can only fix the fix once a day, as it will break every 24 hours. I think I need outside help with a new vision of the problem. Am I missing something? Is there any OS dependency that VAPID is using and needs to be restarted?


Here are some code snippets you might find useful. Sorry for the mess, but I did a few modifications to try and get it to 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 re-subscription

# 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)

      

Calling back over the Internet:

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

      

+3


source to share


2 answers


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



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
  }
)

      

+1


source


It looks like the library has changed, here's 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

      



Note that the key expires, not exp, and the time expires in seconds.

0


source







All Articles