Only this pageAll pages
Powered by GitBook
1 of 21

3.0.x

Loading...

Loading...

Loading...

Loading...

Loading...

Common Concepts

Loading...

Loading...

Loading...

Loading...

Loading...

The Library

Loading...

Loading...

Loading...

The Symfony Bundle

Loading...

Loading...

Loading...

Loading...

Loading...

Fluent Syntax

In the documentation, you will see that methods are called “fluently”.

<?php

use WebPush\Payload\AES128GCM;
use WebPush\Payload\AESGCM;
use WebPush\Payload\PayloadExtension;

$payloadExtension = PayloadExtension::create()
    ->addContentEncoding(AESGCM::create()->maxPadding())
    ->addContentEncoding(AES128GCM::create()->maxPadding())
;

If you don’t adhere to this coding style, you are free to use the “standard” way of coding. The following example has the same behavior ase above.

<?php

use WebPush\Payload\AES128GCM;
use WebPush\Payload\AESGCM;
use WebPush\Payload\PayloadExtension;

$aesgcm = new AESGCM();
$aesgcm->maxPadding();

$aes128gcm = new AES128GCM();
$aes128gcm->maxPadding();

$payloadExtension = new PayloadExtension();
$payloadExtension->addContentEncoding($aesgcm);
$payloadExtension->addContentEncoding($aes128gcm);

Contributing

First of all, thank you for contributing.

Bugs or feature requests can be posted online on the GitHub issues section of the project.

Few rules to ease code reviews and merges:

  • You MUST run the test suite (see below).

  • You MUST write (or update) unit tests when bugs are fixed or features are added.

  • You SHOULD write documentation.

We use the following branching workflow:

  • Each minor version has a dedicated branch (e.g. v1.1, v1.2, v2.0, v2.1…)

  • The default branch is set to the last minor version (e.g. v2.1).

Your PR should NOT be submitted to the master branch but to the last minor version branch or to another minor version in case of bug fix.

Requirements

Mandatory

  • PHP 8.2+

  • The JSON extension

Optional

  • A PSR-3 (Logger Interface) implementation for debugging

Extension Specific

VAPID extension

  • Required:

    • openssl extension

    • mbstring extension

    • A JWT Provider

    • A PSR-20 (Clock) implementation

  • Optional:

    • A PSR-3 (Logger Interface) implementation for debugging

Payload extension

  • Required:

    • openssl extension

    • mbstring extension

  • Optional:

    • A PSR-6 (Caching Interface) implementation

    • A PSR-3 (Logger Interface) implementation for debugging

Overview

The Web Push protocol allows your application to easily engage users by sending notifications to the browser. The subscription to these notifications are done by the user (opt-in).

The notification types depend on the application. For example, it could be a notification for an internal message or an alert before account closure.

We will see in this documentation that the Web Push API offers several options to customize the notifications by adding buttons, vibration schema, images, urgency indictor and more.

You MUST follow the coding standard.

You MAY follow the and .

To contribute use , please, write commit messages that make sense, and rebase your branch before submitting your PR.

This library provides JWT Provider implementations for and

You want to test it? Please go to to see what your browser already supports.

PSR-12
PSR-5
PSR-19
Pull Requests
web-token
lcobucci/jwt
this demo page

VAPID

Voluntary Application Server Identification

“VAPID” stands for “Voluntary Application Server Identification”.

This feature allows to application server to send information about itself to a push service.

A consistent identity can be used by a push service to establish behavioral expectations for an application server. Significant deviations from an established norm can then be used to trigger exception-handling procedures.

Any application server in possession of a push message subscription URI is able to send messages to the user agent.

If use of a subscription could be limited to a single application server, this would reduce the impact of the push message subscription URI being learned by an unauthorized party.

In order to use this feature, you must generate ECDSA key pairs. Hereafter an example using OpenSSL.

openssl ecparam -genkey -name prime256v1 -out private_key.pem
openssl ec -in private_key.pem -pubout -outform DER|tail -c 65|base64|tr -d '=' |tr '/+' '_-' >> public_key.txt
openssl ec -in private_key.pem -outform DER|tail -c +8|head -c 32|base64|tr -d '=' |tr '/+' '_-' >> private_key.txt

Voluntarily provided contact information can be used to contact an application server operator in the case of exceptional situations. Additionally, the design of relies on maintaining the secrecy of push message subscription URIs.

Please refer to for using the VAPID feature.

RFC8030

License

The MIT License (MIT)

Copyright (c) 2020-2023 Spomky-Labs

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Web-Push

Web Notifications made easy

WebPush can be used to send notifications to endpoints which server delivers Web Push notifications as described in the following specifications

The

The

The

In addition, some features from the are implemented. This specification is a working draft at the time of writing (2023-11).

This project allows sending notifications on compatible browsers. List and versions available at

RFC8030: Generic Event Delivery Using HTTP Push
RFC8291: “Message Encryption for Web Push
RFC8292: Voluntary Application Server Identification (VAPID) for Web Push
Push API
https://caniuse.com/push-api

The Notification

To reach the client (web browser), you need to send a Notification to the Subscription.

<?php
use WebPush\Notification;

$notification = Notification::create();

The Notification should have a payload. In this case, the payload will be encrypted on server side and decrypted by the client.

That payload may be a string or a JSON object. The structure of the latter is described in the next section.

<?php
use WebPush\Notification;

$notification = Notification::create()
    ->withPayload('Hello world')
;

TTL (Time-To-Live)

With this feature, a value in seconds is added to the notification. It suggests how long a push message is retained by the push service. A value of 0 (zero) indicates the notification is delivered immediately.

<?php
use WebPush\Notification;

$notification = Notification::create()
    ->withTTL(3600)
;

Topic

A push message that has been stored by the push service can be replaced with new content. If the user agent is offline during the time the push messages are sent, updating a push message avoids the situation where outdated or redundant messages are sent to the user agent.

Only push messages that have been assigned a topic can be replaced. A push message with a topic replaces any outstanding push message with an identical topic.

<?php
use WebPush\Notification;

$notification = Notification::create()
    ->withTopic('user-account-updated')
;

Urgency

For a device that is battery-powered, it is often critical it remains dormant for extended periods.

Radio communication in particular consumes significant power and limits the length of time the device can operate.

To avoid consuming resources to receive trivial messages, it is helpful if an application server can communicate the urgency of a message and if the user agent can request that the push server only forwards messages of a specific urgency.

Urgency
Device State
Examples

very-low

On power and Wi-Fi

Advertisements

low

On either power or Wi-Fi

Topic updates

normal

On neither power nor Wi-Fi

Chat or Calendar Message

high

Low battery

Incoming phone call or time-sensitive alert

Be carful with the very-low urgency: it is not recognized by all Web-Push services

<?php
use WebPush\Notification;

$notification = Notification::create()
    ->veryLowUrgency()
    ->lowUrgency()
    ->normalUrgency()
    ->highUrgency()
;

Asynchronous Response

Your application may prefer asynchronous responses to request confirmation from the push service when a push message is delivered and then acknowledged by the user agent. The push service MUST support delivery confirmations to use this feature.

<?php
use WebPush\Notification;

$notification = Notification::create()
    ->async() // Prefer async response
    ->sync() // Prefer sync response (default)
;

The async mode is not recognised by all Web Push services. In case of failure, you should try sending syncnotifications.

JSON Messages

The library provides a WebPush\Message class with convenient methods to ease the creation of a message.

<?php
use WebPush\Action;
use WebPush\Message;
use WebPush\Notification;

$message = Message::create('This is the title', null, true)
    ->mute() // Silent
    ->unmute() // Not silent (default)

    ->auto() //Direction = auto (default)
    ->ltr() //Direction = left to right
    ->rtl() //Direction = right to left

    ->addAction(Action::create('alert', 'Click me!'))

    ->interactionRequired()
    ->noInteraction()

    ->renotify()
    ->doNotRenotify() // Default
    
    ->withBody('Hello World!')

    ->withIcon('https://…')
    ->withImage('https://…')
    ->withData(['foo' => 'BAR']) // Arbitrary data
    ->withBadge('badge1')
    ->withLang('fr-FR')
    ->withTimestamp(time())
    ->withTag('foo')

    ->vibrate(300, 100, 400)

    ->toString() // Converts the Message object into a string
;

$notification = Notification::create()
    ->withPayload($message)
;

The resulting notification payload will look like as follow:

{
    "title":"This is the title",
    "options":{
        "actions":[
            {
                "action":"alert",
                "title":"Click me!"
            }
        ],
        "badge":"badge1",
        "body":"Hello World!",
        "data":{
            "foo":"BAR"
        },
        "dir":"rtl",
        "icon":"https://…",
        "image":"https://…",
        "lang":"fr-FR",
        "renotify":false,
        "requireInteraction":false,
        "silent":false,
        "tag":"foo",
        "timestamp":1629145424,
        "vibrate":[
            300,
            100,
            400
        ]
    }
}

On client side, you can easily load that payload and display the notification:

  const {title, options}  = payload;
  const notification = new Notification(title, options);

As mentioned in the overview section, the specification . This structure contains properties that the client should be understood and render an appropriate way.

defines a structure for the payload

The Subscription

The subscription is created on client side when the end-user allows your application to send push messages.

On client side (Javascript), you can simply send to your server the object you receive using JSON.stringify.

Javascript examples to get a Subscription from the web browser are not provided here. Please refer to other resources such as blog posts or library documentation.

A subscription object will look like:

On server side, you can get a WebPush\Subscription object from the JSON string using the dedicated method WebPush\Subscription::createFromString.

Supported Content Encodings

By default, the content encoding aesgcm will be used. This encoding indicates how the payload of the notification should be formatted. The PushManager object from the Push API may list all acceptable encodings. In this case, it could be interesting to set these encodings to the Subscription object.

This will result in something like as follow:

The order of supportedContentEncodings is important. First supported item will be used. If possible, AES128GCM should be used as prefered content encoding.

Illustration by Freepik Stories (https://stories.freepik.com/communication)
{
 "endpoint":"https://updates.push.services.mozilla.com/wpush/v2/AAAAAAAA[…]AAAAAAAAA",
 "keys":{
 "auth":"XXXXXXXXXXXXXX",
 "p256dh":"YYYYYYYY[…]YYYYYYYYYYYYY"
 }
}
<?php

use WebPush\Subscription;

$subscription = Subscription::createFromString('{"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/AAAAAAAA[…]AAAAAAAAA","keys":{"auth":"XXXXXXXXXXXXXX","p256dh":"YYYYYYYY[…]YYYYYYYYYYYYY"}}');
// Retreive the supported content encodings
const supportedContentEncodings = PushManager.supportedContentEncodings || ['aesgcm'];

// Assign the encodings to the subscription object
const jsonSubscription = Object.assign(
    subscription.toJSON(),
    { supportedContentEncodings }
);

// Send the subscription object to the application server
fetch('/subscription/add', {
    method: 'POST',
    body: JSON.stringify(jsonSubscription),
});
{
 "endpoint":"https://updates.push.services.mozilla.com/wpush/v2/AAAAAAAA[…]AAAAAAAAA",
 "keys":{
 "auth":"XXXXXXXXXXXXXX",
 "p256dh":"YYYYYYYY[…]YYYYYYYYYYYYY",
 "supportedContentEncodings":["aes128gcm","aesgcm"]
 }
}

The Web Push Service

The bundle provides a public Web Push service that you can inject this service into your application components.

In the following example, let's imagine that a notification is dispatched using the Symfony Messanger component and catched by an event handler. This handler will fetch all subscriptions and send the notification.

The SubscriptionRepository class is totally fictive

src/MessageHandler/SendNotification.php
<?php

declare(strict_types=1);

namespace App\MessageHandler;

use App\Message\SubscriptionExpired;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use WebPush\Notification;
use WebPush\WebPush;

final class SendPushNotifications implements MessageHandlerInterface
{
    private MessageBusInterface $messageBus;
    private SubscriptionRepository $repository;
    private WebPush $webPush;

    public function __construct(MessageBusInterface $messageBus, SubscriptionRepository $repository, WebPush $webPush)
    {
        $this->messageBus = $messageBus;
        $this->repository = $repository;
        $this->webPush = $webPush;
    }

    public function __invoke(Notification $notification): void
    {
        // Fetch all subscriptions
        $subscriptions = $this->repository->fetchAllSubscriptions();
        foreach ($subscriptions as $subscription) {
            //Sends the notification to the subscriber
            $report = $this->webPush->send($notification, $subscription);

            //If the subscription expired
            if ($report->subscriptionExpired()) {
                //We dispatch a new message and expect for
                // the subscription to be deleted
                $this->messageBus->dispatch(
                    new SubscriptionExpired($subscription)
                );
            }
        }
    }
}

Doctrine

The bundle provides new Doctrine type and Schema to simplify the way you store the Subscription objects with Doctrine.

Using The Doctrine Mapping

Configuration

To enable this feature, the following configuration option shall be set:

webpush:
    doctrine_mapping: true

This will tell the bundle to register the Subscription object as a Doctrine mapped-superclass. The DoctrineBundle shall be enabled. No additional configuration is required.

The Subscription Entity

First of all, we need to create a Subscription Entity that extends the Subscription object. In this example, we also need to associate one or more Subscription entities to a specific user (Many To One relationship).

src/Entity/Subscription.php
<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use WebPush\Subscription as WebPushSubscription;

#[ORM\Table(name: 'subscriptions')]
#[ORM\Entity]
class Subscription extends WebPushSubscription
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer')]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: User::class, cascade: ['persist'], inversedBy: 'subscriptions')]
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: true)]
    
    private ?User $user;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getUser(): ?User
    {
        return $this->user;
    }

    public function setUser(?User $user): self
    {
        $this->user = $user;

        return $this;
    }

    // We need to override this method as it returns a WebPush\Subscription and we want an entity
    public static function createFromString(string $input): self
    {
        $base = BaseSubscription::createFromString($input);
        $object = new self($base->getEndpoint());
        $object->withContentEncodings($base->getSupportedContentEncodings());
        foreach ($base->getKeys()->all() as $k => $v) {
            $object->getKeys()->set($k, $v);
        }

        return $object;
    }
}

In this exaple, we assume you already have a valid User entity class.

The User Entity

Now, to have a bidirectional relationship between this class and the User entity class, we will add this relationship to the User class.

src/Entity/User.php
<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="users")
 * @ORM\Entity
 */
#[ORM\Table(name: 'users')]
#[ORM\Entity]
class User //Usual interface here
{
    //Usual user stuff here

    #[ORM\OneToMany(targetEntity: Subscription::class, mappedBy: 'user')]
    private Collection $subscriptions;

    public function __construct()
    {
        $this->notifications = new ArrayCollection();
    }

    /**
     * @return Notification[]
     */
    public function getSubscriptions(): array
    {
        return $this->notifications->toArray();
    }

    public function addSubscription(Subscription $subscription): self
    {
        $subscription->setUser($this);
        $this->subscriptions->add($subscription);

        return $this;
    }

    public function removeSubscription(Subscription $subscription): self
    {
        $child->setUser(null);
        $this->subscriptions->removeElement($subscription);

        return $this;
    }
}

Sending Notifications To A User

Now that your entities are set, you can register Subcriptions and assign them to your users. To send a Notification to a specific user, you just have to get all subscriptions using $user->getSubscriptions().

$subscriptions = $user->getSubscriptions();
foreach ($subscriptions as $subscription) {
    $report = $this->webPush->send($notification, $subscription);
    if ($report->isSubscriptionExpired()) {
        //...Remove this subscription
    }
}

Using Your Own Entity Class

It is possible to use your own Subscription entity class. The only constraint is that it shall implement the interface WebPush\SubscriptionInterface or shall have a method that returns an object that implements this interface.

The Web Push Service

In this example, we load the Subscription object from a string, but usually to retrieve the Subscription objects from a database or a dedicated storage.

The WebPush object requires a and an .

The service is now ready to send Notifications to the Subscriptions. The StatusReport object that is returned .

use Symfony\Component\HttpClient\HttpClient;
use WebPush\WebPush;

$client = HttpClient::create();

$service = new WebPush($client, $extensionManager);
<?php

use WebPush\Subscription;
use WebPush\Notification;

$subscription = Subscription::createFromString('{"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/AAAAAAAA[…]AAAAAAAAA","keys":{"auth":"XXXXXXXXXXXXXX","p256dh":"YYYYYYYY[…]YYYYYYYYYYYYY"}}');
$notification = Notification::create()
    ->withPayload('Hello world')
;

$statusReport = $service->send($notification, $subscription);
HTTP Client
Extension Manager
is explained here
this page

The Extension Manager

The Web Push service requires an Extension Manager. This object manages extensions that will manipulate the request before sending it to the Push Service.

In the example below, we add all basic extensions.

use WebPush\ExtensionManager;
use WebPush\PreferAsyncExtension;
use WebPush\TopicExtension;
use WebPush\TTLExtension;
use WebPush\UrgencyExtension;

$extensionManager = ExtensionManager::create()
    ->add(TTLExtension::create())
    ->add(UrgencyExtension::create())
    ->add(TopicExtension::create())
    ->add(PreferAsyncExtension::create())
;

Please note that the TTL Extension is usually required by Push Services. To avoid any trouble, please use all extensions.

Payload Extension

The payload extension allows Notifications to have a payload. This extension requires Content Encoding objects that will be responsible of the payload encryption.

The library provides the AESGCM and AES128GCM content encoding. These encodings are normally supported by all Push Services. The library is able to support any future encoding is deemed necessary.

$clock = //PSR-20 clock
$payloadExtension = PayloadExtension::create()
    ->addContentEncoding(AESGCM::create($clock))
    ->addContentEncoding(AES128GCM::create($clock))
;

$extensionManager = ExtensionManager::create()
    ->add($payloadExtension)
;

VAPID Extension

The library provides bridges for the following libraries web-token and lcobucci/jwt.

Please install web-token/jwt-signature-algorithm-ecdsa or lcobucci/jwt depending on the library you want to use.

use WebPush\VAPID\WebTokenProvider;
use WebPush\VAPID\LcobucciProvider;

// Web-Token
$jwsProvider = WebTokenProvider::create(
    'BB4W1qfBi7MF_Lnrc6i2oL-glAuKF4kevy9T0k2vyKV4qvuBrN3T6o9-7-NR3mKHwzDXzD3fe7XvIqIU1iADpGQ', // Public key
    'C40jLFSa5UWxstkFvdwzT3eHONE2FIJSEsVIncSCAqU' // Private key
);

// lcobucci/jwt
$jwsProvider = LcobucciProvider::create(
    'BB4W1qfBi7MF_Lnrc6i2oL-glAuKF4kevy9T0k2vyKV4qvuBrN3T6o9-7-NR3mKHwzDXzD3fe7XvIqIU1iADpGQ',
    'C40jLFSa5UWxstkFvdwzT3eHONE2FIJSEsVIncSCAqU'
);

$extensionManager = ExtensionManager::create()
    ->add(VAPIDExtension::create('http://my-service.com', $jwsProvider)
);

The public key used with your server shall be the same as the one in your Javascript application.

If this public/private key changes, subscriptions will become invalid.

The authenticates your server and prevent malicious application to send notifications to your users. The header contains a signed JSON Web Token (JWS).

VAPID header

The Status Report

After sending a notification, you will receive a StatusReport object.

This status report has the following properties:

  • The status code

  • The notification URL (refers to the push service provider)

  • The links for push notification management

Depending on the status code, you will be able to know if it is a success or not. In case of success, you can directly access the management link (location header parameter) or the links entity fields in case of asynchronous call. In case of failure, the response code indicates the main reason for rejection (invalid authorization token, expired endpoint...)

<?php
use WebPush\Subscription;
use WebPush\Notification;
use WebPush\WebPushService;

/** @var Notification $notification */
/** @var Subscription $subscription */
/** @var WebPushService $webPushService */
$statusReport = $webPushService->send($notification, $subscription);

if(!$statusReport->isSuccess()) {
    //Something went wrong
} else {
    $statusReport->getLocation();
    $statusReport->getLinks();
}

One of the failure reasons could be the expiration of the subscription (too old or cancelled by the end-user). This can be checked with the method isSubscriptionExpired(). In this case, you should simply delete the subscription as it is not possible to send notifications anymore.

<?php

if($statusReport->isSubscriptionExpired()) {
    $this->subscriptionRepository->remove($subscription);
}

Installation

The library can be installed using the package spomky-labs/web-push-lib

composer require spomky-labs/web-push-lib

VAPID Header

The library provides bridges for the following libraries web-token and lcobucci/jwt.

Please install web-token/jwt-signature-algorithm-ecdsa or lcobucci/jwt depending on the library you want to use.

It is possible to use any other JWS provider. This will be detailed in the future.

The

The

The authenticates your server and prevent malicious application to send notifications to your users. The header contains a signed JSON Web Token (JWS).

notification
subscription
VAPID header

Installation

The bundle can be installed using the package spomky-labs/web-push-bundle

composer require spomky-labs/web-push-bundle

If you use Symfony Flex, the bundle is ready to be used. Otherwise, you must enable it. The bundle class is WebPush\Bundle\WebPushBundle.

When done, the bundle is ready and can send the notifications. However, there are extra packages we highly recommend to install and set up.

VAPID Header

The library provides bridges for the following libraries web-token and lcobucci/jwt.

Please install web-token/jwt-signature-algorithm-ecdsa or lcobucci/jwt depending on the library you want to use.

It is possible to use any other JWS provider. This will be detailed in the future.

The authenticates your server and prevent malicious application to send notifications to your users. The header contains a signed JSON Web Token (JWS).

VAPID header

Configuration

VAPID Support

config/packages/webpush.yaml
webpush:
  vapid:
    enabled: true # Enable the feature
    subject: 'https://my-service.com:8000' # An URL or an email address
    web_token:
      enabled: true # We use web-token in this example
      public_key: 'BB4W1qfBi7MF_Lnrc6i2oL-glAuKF4kevy9T0k2vyKV4qvuBrN3T6o9-7-NR3mKHwzDXzD3fe7XvIqIU1iADpGQ'
      private_key: 'C40jLFSa5UWxstkFvdwzT3eHONE2FIJSEsVIncSCAqU'

When using lcobucci/jwt, the configuration is very similar.

config/packages/webpush.yaml
webpush:
  vapid:
    enabled: true
    subject: 'https://my-service.com:8000'
    lcobucci:
      enabled: true # We use web-token in this example
      public_key: 'BB4W1qfBi7MF_Lnrc6i2oL-glAuKF4kevy9T0k2vyKV4qvuBrN3T6o9-7-NR3mKHwzDXzD3fe7XvIqIU1iADpGQ'
      private_key: 'C40jLFSa5UWxstkFvdwzT3eHONE2FIJSEsVIncSCAqU'

You cannot enable both web-token and lcobucci/jwt at the same time

Token Lifetime

config/packages/webpush.yaml
webpush:
  vapid:
    enabled: true
    token_lifetime: 'now +2 hours'

The token lifetime should not be greater than 24 hours. Most of the Web Push Services will reject such long-life tokens

Payload Support

Padding

To obfuscate the real length of the notifications, messages can be padded before encryption. This operation consists in the concatenation of your message and arbitrary data in front of it. When encrypted, the messages will have the same size which reduces attacks.

By default, the padding is set to recommended i.e. ~3k bytes.

Acceptable values for this parameter are:

  • none: no padding

  • recommended: default value

  • max: see warning below

  • an integer: should be between 0 and 4078 or 3993 for AESGCM and AES128GCM respectively

config/packages/webpush.yaml
webpush:
  payload:
    aesgcm:
      padding: 'none' # "none", "recommended", "max" or an integer (0 to 4078)
    aes128gcm:
      padding: 'none' # "none", "recommended", "max" or an integer (0 to 3993)

Please don't use "none" unless your are sending notifications in a development environment.

The value "max" increases the integrity protection of the messages, but there are known issues on Android and notification are not correctly delivered.

Caching

The creation of this random key takes approximately 150ms and can impact your server performance when sending thousand of notifications at once.

To reduce the impact on your server, you can enable the caching feature and reuse the encryption key for a defined period of time.

As encryption keys will be stored in the cache, you should make sure the cache is not shared otherwise you may have a security issue.

This parameter requires a PSR-6 Cache compatible service. If you set Psr\Log\CacheItemPoolInterface, the default Symfony cache will be used.

config/packages/webpush.yaml
webpush:
  payload:
    aesgcm:
      cache: Psr\Cache\CacheItemPoolInterface
      cache_lifetime: '+1 hour' #Default: now +30min
    aes128gcm:
      cache: Psr\Cache\CacheItemPoolInterface
      cache_lifetime: '+1 hour' #Default: now +30min

Debugging

If you have troubles sending notifications, you can log some messages from the libray. To do so, you just have to set the parameter logger in the configuration.

This parameter requires a PSR-3 logger. If you set Psr\Log\LoggerInterface, the Symfony logger will be used (PSR-3 copmpatible).

config/packages/webpush.yaml
webpush:
  logger: Psr\Log\LoggerInterface

To enable the VAPID header feature, you must install a JWS Provider (see ) and configure it with your public and private key (see to create these keys)

By default, the library generates VAPID headers that are valid for 1 hour. You can change this value if needed. The parameter requires a relative string as showed .

The notifications . This payload is encrypted on server side and, during this process, a random key is generated.

You can see the impact of this feature on the CI/CD Pipelines of this library. Go the and find a summary table displayed at the end of each test.

installation
this page
in the PHP documentation
https://github.com/Spomky-Labs/web-push/actions?query=workflow%3ABenchmark
may have a payload

Example

Please have a look at the demo available at .

https://github.com/Spomky-Labs/web-push-demo