Web Push (VAPID)
RFC 8292 Voluntary Application Server Identification (VAPID) for Web Push (RFC 8030). Operators sign JWTs with an ECDSA-P256 key to identify themselves to the push service; the browser-side subscription includes the operator's VAPID public key in applicationServerKey. RFC 8292 §3 mandates ES256; the framework uses node:crypto for ECDSA because the protocol is not PQC-yet (browser push services don't accept ML-DSA today; track draft-ietf-webpush-vapid-pqc for the migration).
b.webPush.buildVapidAuthHeader({ subscription, contact, privateKeyPem, publicKeyPem }) returns the Authorization: vapid t= header value the operator sets on the push-request POST to the push-service endpoint.
b.webPush.generateVapidKeypair() returns { publicKeyPem, privateKeyPem, publicKeyB64Url } — the b64url-encoded public key is what the browser code passes as applicationServerKey.
b.webPush.generateVapidKeypair() #
Generate a fresh ECDSA-P256 keypair suitable for VAPID. Returns { publicKeyPem, privateKeyPem, publicKeyB64Url }. The b64url- encoded public key is what the browser code passes as applicationServerKey to pushManager.subscribe.
var kp = b.webPush.generateVapidKeypair();
// Browser:
// pushManager.subscribe({ applicationServerKey: kp.publicKeyB64Url })
b.webPush.buildVapidAuthHeader(opts) #
{
subscription: { endpoint: string }, // browser-returned subscription
contact: string, // mailto:... or https:... per RFC 8292 §2
privateKeyPem: string, // ECDSA-P256 PEM-encoded private key
publicKeyB64Url: string, // public key from generateVapidKeypair()
ttlSec: number, // optional, default 12h
}
Build the Authorization: vapid t= header value per RFC 8292 §3. The JWT claims (aud / exp / sub) are computed from the subscription endpoint origin + operator contact; exp defaults to 12 hours (RFC 8292 §2 caps at 24 hours).
var hdr = b.webPush.buildVapidAuthHeader({
subscription: { endpoint: "https://fcm.googleapis.com/wp/abc" },
contact: "mailto:ops@example.com",
privateKeyPem: kp.privateKeyPem,
publicKeyB64Url: kp.publicKeyB64Url,
});
// → "vapid t=, k="
b.webPush.encrypt(opts) #
{
subscription: { endpoint, keys: { p256dh, auth } },
payload: Buffer|string,
ttlSec: number, // default 28d (RFC 8030 §5.2)
}
Encrypt a Web Push message payload per RFC 8291 (Message Encryption for Web Push) using the aes128gcm content-coding per RFC 8188. Returns { body, headers }: - body is the Buffer to POST to the subscription endpoint - headers carries the spec-required Content-Encoding + Content-Length + TTL (caller-overridable) so operators wire them onto the push-request alongside the VAPID Authorization.
The recipient's subscription object provides p256dh (their ECDH P-256 public key, base64url) and auth (16-byte auth secret, base64url). The framework computes the ephemeral keypair, performs ECDH, runs the two-stage HKDF per RFC 8291 §3.4, and AES-128-GCM encrypts with the padded plaintext per RFC 8188 §2.
var e = b.webPush.encrypt({
subscription: { endpoint: sub.endpoint, keys: { p256dh, auth } },
payload: "hello",
});
b.httpClient.request({
url: sub.endpoint, method: "POST",
headers: Object.assign({}, e.headers, {
Authorization: vapidHeader,
}),
body: e.body,
});
Last updated 2026-08-08T16:39:49.652Z by seeder.