Debugging Web Push in Mozilla Firefox

Introduction

This article is part of an ongoing series about using and working with Web Push and Mozilla’s Web Push service. This article is not meant to be a general guide, but instead offers suggestions and insight into best using the service. Some knowledge of Javascript, Python, or other technologies is presumed.

One of the challenges with Web Push implementation issues is trying to figure out what went wrong. Web Push has a large number of “moving parts”, systems and components that need to work together in order for your message to be successfully sent and received. While this article can’t address all the reasons that a given Push message might fail, I will try to provide tools and guidance for the more common problems.

Common Problems

Error reporting

The largest problem we see is from sites that do not pay attention to the return codes we provide. A previous post mentioned how you can manage subscriptions to reduce your cost of sending out messages that will never be delivered. It’s also important to pay attention to the error that is returned.

The list of errno values are available in the Autopush documentation. (Autopush is the name of the open source server we run to handle receiving and forwarding push subscription updates.) The server tries to provide as much detail and help as possible, so if your messages aren’t getting through, the Autopush messages may help quite a bit.

VAPID concerns

Another potential problem is confusion around VAPID. VAPID is a developing specification for subscription-providing sites to “self identify”. This means that if there’s a significant problem, the push server operator has a way to contact whomever is sending the problematic messages. If you are seeing a large number of “401” status code response messages, chances are you have a problem with your VAPID authentication.

VAPID also allows a site to create “restricted subscriptions“. These subscriptions are locked down so that only the party that has the VAPID key can send them. This can be a bit confusing.

Very simply, VAPID is a block of data cryptographically signed with a key that has two parts: a Private key that you never share and is used to sign the VAPID token, and a Public key that is safe to share and is used to create the restricted subscription. Generally, you have a VAPID key that lasts for quite some time. It’s not a good idea to have it last forever, but it can certainly last for a year or so. I’ll talk about the implications of that in a bit.

When your app requests a push endpoint, you have the option of providing your VAPID Public key as the applicationServerKey. This will create a new subscription endpoint that is locked to that key. In order to send a successful subscription request, you must sign the VAPID block using the corresponding Private key, and include the Public key with your request. (How you include the public key changed between Draft 01 and Draft 02. You probably want to find a library that does the signing. You’ll also want to consult the documentation for the push service you choose to see which forms they accept. Most push platforms accept Draft 02.)

Note that the VAPID Public key is tied to the URL that you’ve requested. That means that you need to use that same key pair every time you want to send data to that URL. If you ever want to change the VAPID key, you’ll need to fetch a new endpoint and discard the old one. You decide how to do this, of course. Your app could simply fetch the new Public key from a known location, generate a new URL request and send the new registration information back to your server. This exercises much of the same code that you would want in place for a pushsubscriptionchange event.

So, for VAPID 401 errors, you will want to check:

Are you using the same key pair you used to acquire the restricted subscription?

Have you properly signed your VAPID authorization key?

Have you included all required VAPID headers with your request?

Data encryption

Finally, there’s the actual message encryption. This can be the trickiest to debug because the push server has no way of knowing if the encryption is correct when it accepts a message for delivery. In addition, a message is only delivered by the User Agent (UA) if the UA can successfully decrypt it. This prevents your app from waking up to false messages, which can drain battery life.

Again, the best way to solve these sorts of problems is to use a library. This isn’t always possible, and you may have a situation where you need to “hand roll” your own. There is a page that can help walk you through the process of encrypting your data, however it currently only works on Firefox.

Be advised that there are several changes in the specs that may not be supported yet. As of publication date, most push implementations will accept ECE Draft 03 “aesgcm” encoding. There is a proposal that the User Agent report back the forms of cryptography it supports, but this has not been formally accepted yet. Unfortunately, this is one of the issues with using a technology that’s still in development. If you wish to follow the changes that are being proposed, you should follow the working groups.

Unfortunately, many encryption errors are not detected by the Push Service. This is because the Push Service cannot decrypt your message. Fortunately, it is possible to “peek inside” the client to see if there might be an error.

Debugging the Desktop

Use the Browser Console to help debug the desktop. Note, this is different than the “Web Console” that appears as part of the developer tools panel. The Browser Console displays much higher level messages that may not be visible to the page or the web console.

The benefit is that you will be able to see messages that your service worker may log, as well as other push messages. For instance, if you look at a testing page that we use, you might see something similar in your browser:

An example of the browser console output

Near the bottom of that window, you’ll notice four messages from “sw.js”. The first three are console.info() messages stating that a new message has arrived, what the content of the new message is, and the associated clients. Note that the fourth message is a console.error() saying "Service worker couldn't send message: Error: No valid client to send to." This can happen when a service worker loses its claimed association with the parent. In short: the good news is that the message came in fine, the bad news is it had nowhere to go.

Another useful tool to consider is the service worker debugging page at about:debugging#workers. This page shows all the registered service worker scripts and allows you to unregister them, optionally send push events, and debug the service worker scripts. Mozilla Hacks has more details about the about:debugging page.

Debugging Android

Debugging push on Android is somewhat similar. Much like the desktop, you will want to set dom.push.debug to true and dom.push.loglevel to debug. Unfortunately, unlike the desktop, there is no easy way to view the browser console from Android. Messages are logged to the android error log, so it’s possible to use a command like adb logcat to tail the error log. Some developers may be able to use grep to look for only records containing "Gecko(Push|Console)".

Sadly, this view isn’t quite as pretty, but does show much the same, including console messages from service workers which may help identify and resolve bugs. It is worth noting that adb may truncate very long messages.

Note that you get a bit more information here, including messages indicating that GCM received the message and relayed it to Gecko. Many log messages have been removed or trimmed for space for publication, but these can help isolate if the problem is in your app vs. in the network.

Conclusion

Working with Push is rewarding, but remember that it is a new technology. This means that things can change, and there may be rough bits to watch out for. As always, we appreciate bugs when you find them and suggestions on how to make things easier. You can find us on irc.mozilla.org in the #push channel if you have questions.

@Alfonso, thanks for reading and noting! Actually, it’s a little more subtle/complicated – we’ve transitioned the series about Push from the Mozilla Services blog to this one, so there is no single category URL to include them all! :-)

Future developer-facing posts about Push will likely find their way here. Plus, we’ve covered Push in the past as well. Thanks to your suggestion, we now have a Web Push category you can follow going forward: