Push

Notifications push pour navigateurs

Envoyez aux navigateurs de vos utilisateurs la même notification push qu’à leurs téléphones : Chrome, Edge, Firefox et Safari, par le service push du navigateur.

Clés VAPID

Les navigateurs n’acceptent que les notifications signées avec la clé utilisée par le site lors de l’abonnement (VAPID). honkio crée une paire de clés pour chaque application push à sa création. La clé publique figure sur l’application dans web.vapid_public_key et sur la page de l’application dans le tableau de bord; votre site la transmet au navigateur lors de l’abonnement. La clé privée est chiffrée au repos et n’est jamais affichée ni renvoyée.

Vous changez de fournisseur? Importez la paire avec laquelle vos navigateurs se sont déjà abonnés : ils continuent de recevoir sans se réabonner. Générer une nouvelle paire, ou en importer une différente, retire chaque navigateur enregistré sur l’application, en production et en mode test : chacun est désactivé avec la raison VAPID_KEY_REPLACED, car son service push refuserait la nouvelle signature, et un seul webhook push_app.vapid_key_replaced indique combien dans chaque mode (il n’y a pas de push_device.deactivated pour chacun). Un navigateur revient lorsqu’il se réabonne avec la nouvelle clé publique (l’outil le fait lorsque votre page appelle subscribe()). Réimporter la paire déjà en place ne retire rien. Les deux exigent une clé de production, et une vérification supplémentaire dans le tableau de bord.

Node.js
// No keys: generate a new pair. Both keys: import the pair your browsers subscribed with.
const { data: pushApp, error } = await honkio.push.web.setVapidKeys('APP_ID', {
  publicKey: process.env.VAPID_PUBLIC_KEY ?? '',
  privateKey: process.env.VAPID_PRIVATE_KEY ?? '',
})
if (error) throw new Error(error.message)
console.log(pushApp.web?.vapid_public_key)

Chaque notification porte un contact pour les services push (le sujet VAPID) : https://honkio.ca, sauf si vous indiquez le vôtre avec web_push_subject dans PATCH /v1/push/apps/:id. Il doit vous appartenir : un mailto: de l’adresse courriel vérifiée de votre compte, ou une adresse mailto: ou une URL https: sur l’un de vos domaines d’envoi vérifiés (un nom sous l’un d’eux compte aussi). Tout autre sujet est refusé avec 422 VALIDATION_ERROR. Si le domaine cesse d’être vérifié, les notifications partent avec la valeur par défaut jusqu’à ce qu’il le soit de nouveau. Le changer conserve la paire de clés.

Côté navigateur : @honkio/web-push

Le paquet @honkio/web-push enregistre votre service worker, demande l’autorisation, abonne le navigateur et remet l’abonnement à votre serveur. Il n’appelle jamais honkio et ne contient aucune clé d’API : votre clé reste sur votre serveur.

bash
npm install @honkio/web-push

Dans votre service worker, installHonkioPush affiche chaque notification et ouvre data.url (un chemin de votre site) au clic.

javascript
// public/sw.js (bundled, or with an import map)
import { installHonkioPush } from '@honkio/web-push/sw';

installHonkioPush(self, {
  icon: '/icon-192.png',
  defaultTitle: 'Acme',
});

Sur votre page, appelez subscribe() à partir d’un clic, avec la clé publique de votre application et une fonction qui envoie l’abonnement à votre serveur.

javascript
import { subscribe, unsubscribe, isSupported } from '@honkio/web-push';

button.addEventListener('click', async () => {
  if (!isSupported()) return;
  await subscribe({
    vapidPublicKey: 'BEl62iUY...',      // your push app's public key
    serviceWorker: '/sw.js',
    sendSubscription: (subscription) =>
      fetch('/api/push-subscriptions', {   // your backend, not HonkIO
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(subscription),
      }),
  });
});

Safari et Firefox ne demandent l’autorisation qu’après un clic ou un toucher. Sur iPhone et iPad, le web push fonctionne pour les sites ajoutés à l’écran d’accueil (iOS et iPadOS 16.4 et versions ultérieures).

Il arrive qu’un navigateur remplace un abonnement de lui-même. Passez onSubscriptionChange à installHonkioPush pour recevoir le nouvel abonnement dans votre service worker et l’envoyer à votre serveur, qui l’enregistre de nouveau; l’outil n’appelle jamais honkio lui-même.

Enregistrer le navigateur

Votre serveur enregistre l’abonnement sous l’identifiant de l’utilisateur avec PUT /v1/push/devices, platform web et subscription tel que le navigateur l’a donné. Une notification envoyée à ce user_id atteint alors ses navigateurs autant que ses téléphones, tout comme une notification Notify. Comme pour un téléphone, la clé doit avoir la permission push_devices (w pour enregistrer, d pour retirer); un navigateur n’envoie pas de encryption_public_key.

// Your backend, with the subscription your page sent it (@honkio/web-push).
const { data: device, error } = await honkio.push.devices.register({
  appId: 'APP_ID',
  platform: 'web',
  userId: 'user_1042',
  subscription: {
    endpoint: 'https://fcm.googleapis.com/fcm/send/SUBSCRIPTION_ID',
    expirationTime: null,
    keys: { p256dh: 'BROWSER_P256DH_KEY', auth: 'BROWSER_AUTH_SECRET' },
  },
})
if (error) throw new Error(error.message)
console.log(device.id, device.platform)

honkio n’envoie qu’aux services push des fabricants de navigateurs, en HTTPS. Un abonnement dont l’adresse est ailleurs est refusé avec 422 VALIDATION_ERROR, et l’adresse est vérifiée de nouveau avant chaque envoi.

Service pushHôte de l’adresse
Google (Chrome, Edge sur Android, Opera, Samsung Internet)fcm.googleapis.com
Mozilla (Firefox)*.push.services.mozilla.com
Apple (Safari)web.push.apple.com
Microsoft (Edge sur Windows)*.notify.windows.com

L’API ne renvoie jamais l’adresse : un navigateur apparaît dans GET /v1/push/devices avec platform web, comme tout autre appareil. Désabonnez le navigateur avec unsubscribe(), puis retirez l’appareil avec DELETE /v1/push/devices/:id : gardez donc l’identifiant d’appareil renvoyé à l’enregistrement avec l’adresse. Vos propres routes qui reçoivent un abonnement du navigateur devraient exiger la session connectée, enregistrer sous cet utilisateur, et ne modifier ou retirer qu’un abonnement que cet utilisateur a enregistré.

Livraison et prix

Chaque navigateur est une livraison, avec provider webpush. La réponse du service push décide de la suite :

Réponse du service pushCe que fait honkio
201Acceptée. Comptée et facturée comme une notification push mobile. Seul 201 compte : toute autre réponse 2xx est traitée comme non livrée (PROVIDER_ERROR) et remboursée.
404, 410L’abonnement n’existe plus (l’utilisateur s’est désabonné, ou il a expiré). Le navigateur est retiré avec INVALID_TOKEN, push_device.deactivated se déclenche et la livraison est remboursée.
413Trop volumineuse. La livraison échoue avec PAYLOAD_REJECTED, immédiatement et sans nouvel essai. Un navigateur accepte environ 3 990 octets de titre, de corps et de données; un envoi qui ne tiendrait pas est refusé avec 422 PUSH_PAYLOAD_TOO_LARGE avant toute facturation.
429, 5xxOccupé. Réessayé dans la fenêtre de nouvel essai du push, comme pour Apple et Google, en attendant le délai Retry-After du service push s’il en donne un; un Retry-After au-delà de la fenêtre met fin à la livraison avec PROVIDER_UNAVAILABLE.
401, 403Le service push a refusé la signature (abonnement fait avec une autre clé, ou sujet refusé). La livraison échoue avec CREDENTIAL_INVALID et est remboursée, et le navigateur est conservé. Un navigateur refusé cinq fois de suite, sur au moins une journée, est retiré avec VAPID_KEY_MISMATCH et push_device.deactivated se déclenche; une notification acceptée entre-temps remet le compte à zéro.

Le web push coûte le même prix que le push mobile : les livraisons aux navigateurs comptent dans les mêmes 2 500 notifications gratuites par mois, puis 5,00 $ par tranche de 1 000 acceptées. Une livraison non acceptée est remboursée.

En mode test, rien ne va à un service push : la dernière partie de l’adresse est le jeton magique, si bien qu’un abonnement de test à https://fcm.googleapis.com/fcm/send/test_unregistered se comporte comme le jeton d’appareil test_unregistered.

Notifications de données seules

Un navigateur affiche chaque notification qu’il reçoit : il n’y a pas de notification silencieuse en arrière-plan sur le web. Une notification ne contenant que data ferait afficher au navigateur un avis de son cru, et Safari révoque les abonnements qui reçoivent des notifications sans affichage. honkio n’envoie donc jamais une notification de données seules à un navigateur : un envoi à un user_id exclut les navigateurs de cet utilisateur (ils ne reçoivent rien et rien n’est facturé), et un envoi sans titre ni corps au device_id d’un navigateur est refusé avec 422 VALIDATION_ERROR.

Chiffrement

Chaque notification web push est chiffrée de bout en bout jusqu’au navigateur (RFC 8291) : le service push transporte un contenu chiffré qu’il ne peut pas lire, et seul le navigateur abonné peut le déchiffrer. Le chiffrement par appareil de honkio pour iOS et Android (la clé que le paquet push de HonkIO crée sur chaque téléphone) n’est pas utilisé pour les navigateurs, car il n’est pas nécessaire : un navigateur n’enregistre aucune clé d’appareil, et une application qui exige le chiffrement envoie quand même à ses navigateurs.

Les services push voient tout de même l’adresse, l’heure de chaque notification, sa taille, ainsi que la durée de vie, l’urgence et le sujet. Le sujet est toujours une empreinte à clé secrète de votre clé de regroupement, jamais la clé elle-même : le service push ne peut ni retrouver la clé ni confirmer une supposition, et la même clé donne un sujet différent dans chacune de vos applications. Le navigateur reçoit la clé dans le contenu chiffré. Ils conservent une notification destinée à un navigateur hors ligne jusqu’à sa livraison ou son expiration.