|
# Notes from attempting to setup web push notifications
|
|
|
|
## Files included
|
|
|
|
- `service-worker.js` - Service worker file, it listens for push events and displays notifications
|
|
- `example.html` - Main file, it will immediately ask for permission to send notifications and log the subscription object
|
|
to the console. You might have to refresh after giving permissions to see the subscription object.
|
|
|
|
## Steps to setup
|
|
|
|
### Browser setup
|
|
|
|
1. run `npx serve`
|
|
2. Open the browser and go to `http://localhost:3000`
|
|
3. Open the console and you should see the subscription object
|
|
|
|
### Server setup
|
|
|
|
(Or you can use [web-push](https://www.npmjs.com/package/web-push) package)
|
|
|
|
#### Generate VAPID keys
|
|
|
|
1. Run `openssl ecparam -name prime256v1 -genkey -noout -out private.pem`
|
|
1. You might also want to generate a PKCS8 key for the private key
|
|
- Run `openssl pkcs8 -topk8 -nocrypt -in private.pem -out private.pkcs8.pem`
|
|
2. Run `openssl ec -in private.pem -pubout -out public.pem`
|
|
|
|
Now you can your favourite http request library to send a POST request to the url returned by the
|
|
`pushManager.subscribe` method.
|
|
|
|
When you do you should include the following header (and no body!):
|
|
|
|
```http
|
|
TTL: 60
|
|
Authorization: `Bearer ${jwtToken}`
|
|
Crypto-Key: `p256ecdsa=${publicKey}`
|
|
Topic: `An optional topic`
|
|
Urgency: `An optional urgency`
|
|
```
|
|
|
|
The `jwtToken` is a JWT token that you can generate using the private key you generated earlier. The payload should
|
|
include the `aud` field which should be the url returned by the `pushManager.subscribe` method.
|
|
For example:
|
|
|
|
```javascript
|
|
const {default: fs} = await import("fs");
|
|
const {default: crypto} = await import("crypto");
|
|
const {default: jwt} = await import("jsonwebtoken");
|
|
|
|
const privateKeyBuffer = fs.readFileSync('private.pem');
|
|
const privateKey = crypto.createPrivateKey(privateKeyBuffer);
|
|
|
|
const payload = {
|
|
aud: 'https://fcm.googleapis.com',
|
|
sub: 'mailto:example@example.com',
|
|
};
|
|
|
|
const jwtToken = jwt.sign(payload, privateKey, {algorithm: 'ES256', expiresIn: '1h'});
|
|
console.log(jwtToken);
|
|
```
|
|
|
|
It has to use the ES256 algorithm and the `exp` field should be set to a timestamp in the future.
|
|
|
|
The `publicKey` is the public key you generated earlier however it should be encoded as JWK and then base64 url encoded.
|
|
You can use the following code to do that:
|
|
|
|
```javascript
|
|
const {default: fs} = await import("fs");
|
|
const {default: crypto} = await import("crypto");
|
|
|
|
const publicKeyBuffer = fs.readFileSync('public.pem');
|
|
const publicKey = crypto.createPublicKey(publicKeyBuffer);
|
|
|
|
const jwk = {
|
|
kty: 'EC',
|
|
crv: 'P-256',
|
|
x: publicKey.export({format: 'jwk'}).x,
|
|
y: publicKey.export({format: 'jwk'}).y,
|
|
};
|
|
|
|
const base64UrlEncode = (str) => {
|
|
return str.toString('base64')
|
|
.replace(/\+/g, '-')
|
|
.replace(/\//g, '_')
|
|
.replace(/=/g, '');
|
|
};
|
|
|
|
const base64UrlEncodedPublicKey = base64UrlEncode(publicKey.export({format: 'jwk'}).x) + '.' + base64UrlEncode(publicKey.export({format: 'jwk'}).y);
|
|
|
|
console.log(base64UrlEncodedPublicKey);
|
|
```
|
|
|
|
This should be enough to get you started with web push notifications.
|
|
|
|
### Notes
|
|
|
|
- The `pushManager.subscribe` method may require depending on the browser a `userVisibleOnly` field or `applicationServerKey` field. The `userVisibleOnly`
|
|
field should be set to `true` and the `applicationServerKey` field should be set to the public key you generated earlier.
|
|
|
|
- For sending a payload additional changes need to happen, you can't just send a payload with the request.
|
|
- For it to work you will have to update the headers:
|
|
- Encoding the payload, it's complex and I haven't done it yet but you can look at the [Mozilla Blog](https://blog.mozilla.org/services/2016/08/23/sending-vapid-identified-webpush-notifications-via-mozillas-push-service/) for more information.
|
|
- The `Crypto-Key` header should be set to 3 values:
|
|
- `p256ecdsa=${publicKey}` - The public key you generated earlier
|
|
- `dh=${publicHalfKey}` - The first half of the shared secret when the payload is encoded
|
|
- `keyid=p256dh` - The key id
|
|
- The `Encryption` header should be set to 2 values:
|
|
- `salt=${salt}` - The salt used to generate the shared secret
|
|
- `keyid=p256dh` - The key id
|
|
- The `Content-Encoding` header should be set to `aesgcm`
|
|
|
|
For more information you can check the useful links below.
|
|
|
|
### Useful links
|
|
|
|
- [The Web Push Protocol ](https://web.dev/articles/push-notifications-web-push-protocol)
|
|
- [Web Push Book](https://web-push-book.gauntface.com/)
|
|
- [JWT.io](https://jwt.io/)
|
|
- [WebPushDataTestPage](https://mozilla-services.github.io/WebPushDataTestPage/)
|
|
- [Mozilla Blog](https://blog.mozilla.org/services/2016/08/23/sending-vapid-identified-webpush-notifications-via-mozillas-push-service/)
|
|
- [Mozilla docs](https://developer.mozilla.org/en-US/docs/Web/API/PushSubscription) |