web-push-libs / web-push-php

Web Push library for PHP
MIT License
1.68k stars 295 forks source link

web.push.apple.com returns `403 Forbidden` response: {"reason":"BadJwtToken"} #406

Open sunnysideup opened 2 weeks ago

sunnysideup commented 2 weeks ago

We have a user sign up with a MacBook. That works fine. However, when sending, we get this error:

Client error: `POST https://web.push.apple.com/xyz` resulted in a `403 Forbidden` response:
{"reason":"BadJwtToken"}

This is the subscriber data:

{"endpoint":"https://web.push.apple.com/xyz","keys":{"p256dh":"abc","auth":"def"}}

This is the code I use to send:

image

    public function sendPushNotification(PushNotification $notification)
    {
        $subject = Environment::getEnv('SS_VAPID_SUBJECT');
        if (! $subject) {
            user_error('SS_VAPID_SUBJECT is not defined');
        }

        $publicKey = Environment::getEnv('SS_VAPID_PUBLIC_KEY');
        if (! $publicKey) {
            user_error('SS_VAPID_PUBLIC_KEY is not defined');
        }

        $privateKey = Environment::getEnv('SS_VAPID_PRIVATE_KEY');
        if (! $privateKey) {
            user_error('SS_VAPID_PRIVATE_KEY is not defined');
        }

        $auth = [
            'VAPID' => [
                'subject' => $subject,
                'publicKey' => $publicKey,
                'privateKey' => $privateKey,
            ],
        ];

        $icon = static::config()->get('notification_icon');
        if (! is_null($icon) && ! isset(parse_url($icon)['host'])) {
            $icon = Director::absoluteURL($icon);
        }

        $badge = static::config()->get('notification_badge');
        if (! is_null($badge) && ! isset(parse_url($badge)['host'])) {
            $badge = Director::absoluteURL($badge);
        }

        $webPush = new WebPush($auth);

        $payload = json_encode([
            'title' => $notification->Title,
            'body' => $notification->Content,
            'url' => $notification->Link(),
            'icon' => $icon,
            'badge' => $badge,
        ]);

        $subscriptionJsons = [];

        foreach ($notification->getRecipients() as $recipient) {
            $subscriptions = $recipient->PushNotificationSubscribers();
            foreach ($subscriptions as $subscriber) {
                $log = SubscriberMessage::create_new($recipient, $notification, $subscriber);
                $subscription = Subscription::create(json_decode($subscriber->Subscription, true));

                $outcome = $webPush->sendOneNotification($subscription, $payload);

                if ($outcome->isSuccess()) {
                    $subscriptionJsons[$subscriber->ID]['success'] = true;
                    $subscriptionJsons[$subscriber->ID]['outcome'] = 'Success!';
                    $log->Success = true;
                } else {
                    $subscriptionJsons[$subscriber->ID]['success'] = false;
                    $subscriptionJsons[$subscriber->ID]['outcome'] = $outcome->getReason();
                    $log->ErrorMessage = $outcome->getReason();
                    $log->Success = false;
                }
                $log->write();
            }
        }

        return json_encode(['success' => true, 'results' => $subscriptionJsons]);
    }
sunnysideup commented 2 weeks ago

Note that it works a charm on Android

Minishlink commented 2 weeks ago

Hello, set urgency? Also make sure your subject is valid

sunnysideup commented 2 weeks ago

Thank you so much for your quick reply.

The subject is a mailto:myemail@address.com - i.e. not the same domain name as the website - does that matter?

I will try setting the urgency.

Minishlink commented 2 weeks ago

For the subject it should work in theory, although I'm not familiar with Apple's constraints

sunnysideup commented 2 weeks ago

I had my subject slightly different: mailto: <a@b.com>. I have now fixed this. https://stackoverflow.com/questions/75547851/sending-push-notifications-to-safari-from-java