The Push APIs (also known as Web Push) provide the ability for Application Servers (App Servers) to send up to 4 Kilobites of data to applications (apps). In order to do this securely, that data would first need to be encrypted so that it wouldn't be exposed to the push servers in transit. The browser decrypts the data later before delivering it to your app.
Unfortunately, implementing this kind of security is complicated and encryption may be confusing to those not familiar with it.
This page attempts to transparently show the keys and values used to encrypt data for delivery by a push service. It also provides a "working example" of how developers might successfully implement encryption of push notifications for their application or library. Following the steps below, you can see all the "moving parts" in one place and get started adding encryption to your own App Server or library.
This page will presume you're familiar with using push notifications and want to start using the experimental encrypted data payloads. NOTE: This feature is currently experimental, there is very limited library support!
Before getting started, I strongly recommend you first consult: Using the Push APIon MDN (the Mozilla Developer Network). This will help explain how push basic notifications function without data payloads.
Emulating an App Server, this page allows you to do the following:
NOTE: It may be useful to open the Web Debugging Console (Ctrl+Shift+K on Firefox) and note the messages being generated in the console log.
These elements are provided to your web app from the
PushManager
.
call. These values should be relayed directly to your back-end App
Server via your app. Never send this information through the Push
Servers!
subscription.endpoint
is
the URI where you
should POST the encrypted message content. To make things easier,
the page will fetch one for itself. Feel free to replace this with
a different endpoint and key if you wish, and press the "Send Data"
button below to try it out.
subscription.getKey('p256dh')
to retrieve this valuesubscription.getKey('auth')
and is extra data for the
HKDF function, which generates the Shared KeyThese are normally the things you enter for each encrypted push message.
These items (plus the Salt) are unique per encryption, and usually generated "on the fly" by the various algorithms. Key negotiation requires the generation of a Local Key. The Local Key is an arbitrary key pair made for this specific exchange and used to derive bits from the p256dh key.
These items are the various intermediary and final elements used to generate the encryption key.
WebCrypto.deriveBits
call in webpush.js
VAPID is an optional header block that allows senders to "self identify". It consists of a JSON Web Token that contains identification claims.
claims
. "Crypto-Key"
contains a "p256ecdsa" element that specifies the "raw" public key used to verify the JWT signature.
Note that "Crypto-Key" may contain multiple elements separated by a comma. If you specify VAPID
headers, we'll append them to the Crypto-Key header.Crypto-Key
header. This key is in the "uncompressed" or
"raw" key point format.To monitor your push messages, you will add the VAPID public key to your app in the push dashboard. To validate you own the app, you will also need to sign a token with your VAPID private key, and paste the signed token back into the dashboard.
If you are using this page to test, you can paste this test VAPID public key into the dashboard:
Then paste the app token here to get the signed token value:
These are the outputs. You can cut and paste the Curl content and watch the Web Console to see the message be received and handled by the Service Worker.
If you don't have curl, or don't feel like cutting and pasting, you can and this page will do it for you.
If all goes well, you should see something like the following pop up on your screen.
xxd
on Linux systems) to verify that the data is correct.