webpush

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2025 License: MIT Imports: 25 Imported by: 0

README

go-webpush

Go Reference Ask DeepWiki GitHub release (latest SemVer) GitHub Workflow Status

Web Push API encryption and sending library for Go with VAPID support.

This library lets you send encrypted Web Push notifications from a Go server to browsers supporting the Push API. It implements message encryption (aes128gcm), VAPID authentication (JWT over ES256), and useful headers like TTL and Urgency.

Installation

go get github.com/marknefedov/go-webpush

Quick start

  1. Generate VAPID keys (one-time):
package main

import (
    "os"
    webpush "github.com/marknefedov/go-webpush"
)

func main() {
    keys, err := webpush.GenerateVAPIDKeys()
    if err != nil { panic(err) }
    // Persist them somewhere safe; you can export as JSON or PEM
    pem, _ := keys.ExportVAPIDPrivateKeyPEM()
    _ = os.WriteFile("vapid_private.pem", pem, 0o600)
}
  1. On the client, subscribe with the VAPID public key and send the subscription object to your server. See the example directory for a working page and service worker.

  2. Send a push message from your server:

package main

import (
    "context"
    "encoding/json"
    "log"
    "os"
    "time"

    webpush "github.com/marknefedov/go-webpush"
)

func main() {
    // Parse subscription JSON you stored from the browser
    var sub webpush.Subscription
    _ = json.Unmarshal([]byte(`{...}`), &sub)

    // Load your VAPID keys (from PEM)
    keys, err := webpush.LoadVAPIDPrivateKeyPEM(mustRead("vapid_private.pem"))
    if err != nil { log.Fatal(err) }

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    resp, err := webpush.SendNotification(
        ctx,
        []byte("Hello from Go!"), // payload (optional but recommended)
        &sub,
        &webpush.Options{
            Subscriber: "user@example.com", // an email or URL
            VAPIDKeys:  keys,
            TTL:        60,                   // seconds push service should retain the message
            // Urgency: webpush.UrgencyHigh,   // optional: VeryLow, Low, Normal, High
            // Topic:   "demo-1",             // optional: collapse key
        },
    )
    if err != nil { log.Fatal(err) }
    defer resp.Body.Close()
    log.Println("push status:", resp.Status)
}

func mustRead(p string) []byte { b, _ := os.ReadFile(p); return b }

Examples

A complete end-to-end example (CLI sender, HTML page, and service worker) is provided in the example/ directory:

  • example/index.html – subscribe and copy the resulting subscription JSON
  • example/service-worker.js – displays the push
  • example/main.go – generate/load VAPID keys and send a notification

To run the example sender:

cd example
go run .

Then paste the subscription JSON from the page into the terminal when prompted.

Documentation

Index

Constants

View Source
const MaxRecordSize uint32 = 4096

Variables

View Source
var (
	ErrRecordSizeTooSmall = errors.New("record size too small for message")
)

Functions

func EncryptNotification

func EncryptNotification(message []byte, keys Keys, recordSize uint32) ([]byte, error)

EncryptNotification implements the encryption algorithm specified by RFC 8291 for web push (RFC 8188's aes128gcm content-encoding, with the key material derived from elliptic curve Diffie-Hellman over the P-256 curve).

func SendNotification

func SendNotification(ctx context.Context, message []byte, s *Subscription, options *Options) (*http.Response, error)

SendNotification sends a push notification to a subscription's endpoint, applying encryption (RFC 8291) and adding a VAPID header (RFC 8292).

Types

type HTTPClient

type HTTPClient interface {
	Do(*http.Request) (*http.Response, error)
}

HTTPClient is an interface for sending the notification HTTP request / testing

type Keys

type Keys struct {
	Auth   [16]byte
	P256dh *ecdh.PublicKey
}

Keys represent a subscription's keys (its ECDH public key on the P-256 curve and its 16-byte authentication secret).

func DecodeSubscriptionKeys

func DecodeSubscriptionKeys(auth, p256dh string) (keys Keys, err error)

DecodeSubscriptionKeys decodes and validates a base64-encoded pair of subscription keys (the authentication secret and ECDH public key).

func (*Keys) Equal

func (k *Keys) Equal(o Keys) bool

Equal compares two Keys for equality.

func (*Keys) MarshalJSON

func (k *Keys) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler, allowing serialization to JSON.

func (*Keys) UnmarshalJSON

func (k *Keys) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON implements json.Unmarshaler, allowing deserialization from JSON.

type Options

type Options struct {
	HTTPClient      HTTPClient // Will replace it with *http.Client by default if not included
	RecordSize      uint32     // Limit the record size
	Subscriber      string     // Sub in VAPID JWT token
	Topic           string     // Set the Topic header to collapse pending messages (Optional)
	TTL             int        // Set the TTL on the endpoint POST request, in seconds
	Urgency         Urgency    // Set the Urgency header to change a message priority (Optional)
	VAPIDKeys       *VAPIDKeys // VAPID public-private keypair to generate the VAPID Authorization header
	VapidExpiration time.Time  // optional expiration for VAPID JWT token (defaults to now + 12 hours)
}

Options are config and extra params needed to send a notification

type Subscription

type Subscription struct {
	Endpoint       string    `json:"endpoint"`
	Keys           Keys      `json:"keys"`
	ExpirationTime time.Time `json:"expirationTime"`
}

Subscription represents a PushSubscription object from the Push API

type Urgency

type Urgency string

Urgency indicates to the push service how important a message is to the user. This can be used by the push service to help conserve the battery life of a user's device by only waking up for important messages when the battery is low.

const (
	// UrgencyVeryLow requires device state: on power and Wi-Fi
	UrgencyVeryLow Urgency = "very-low"
	// UrgencyLow requires device state: on either power or Wi-Fi
	UrgencyLow Urgency = "low"
	// UrgencyNormal excludes device state: low battery
	UrgencyNormal Urgency = "normal"
	// UrgencyHigh admits device state: low battery
	UrgencyHigh Urgency = "high"
)

type VAPIDKeys

type VAPIDKeys struct {
	// contains filtered or unexported fields
}

VAPIDKeys is a public-private keypair for use in VAPID.

func ECDSAToVAPIDKeys

func ECDSAToVAPIDKeys(privKey *ecdsa.PrivateKey) (result *VAPIDKeys, err error)

ECDSAToVAPIDKeys wraps an existing ecdsa.PrivateKey in VAPIDKeys for use in VAPID header signing.

func GenerateVAPIDKeys

func GenerateVAPIDKeys() (result *VAPIDKeys, err error)

GenerateVAPIDKeys generates a VAPID keypair (an ECDSA keypair on the P-256 curve).

func LoadVAPIDPrivateKeyPEM

func LoadVAPIDPrivateKeyPEM(pemBytes []byte) (*VAPIDKeys, error)

LoadVAPIDPrivateKeyPEM reads a PKCS#8 PEM-encoded private key returns VAPIDKeys.

func (*VAPIDKeys) Equal

func (v *VAPIDKeys) Equal(o *VAPIDKeys) bool

Equal compares two VAPIDKeys for equality.

func (*VAPIDKeys) ExportVAPIDPrivateKeyPEM

func (v *VAPIDKeys) ExportVAPIDPrivateKeyPEM() ([]byte, error)

ExportVAPIDPrivateKeyPEM writes the private key in PKCS#8 PEM format to the specified file. The public key can be obtained later via PublicKeyString.

func (*VAPIDKeys) MarshalJSON

func (v *VAPIDKeys) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler producing Web-push–style JSON:

{"publicKey":"<base64url>", "privateKey":"<base64url>"}

The publicKey is the uncompressed EC point (65 bytes) base64url-encoded. The privateKey is the 32-byte big-endian scalar base64url-encoded.

func (*VAPIDKeys) PrivateKey

func (v *VAPIDKeys) PrivateKey() *ecdsa.PrivateKey

PrivateKey returns the private key of the keypair.

func (*VAPIDKeys) PublicKeyString

func (v *VAPIDKeys) PublicKeyString() string

PublicKeyString returns the base64url-encoded uncompressed public key of the keypair, as defined in RFC8292.

func (*VAPIDKeys) UnmarshalJSON

func (v *VAPIDKeys) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaler accepting only Web-push–style JSON ({"publicKey":"...","privateKey":"..."}). PublicKey is ignored if present.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL