microsoft-edgeweb-push

Edge Web Push Notifications - 400 Error, no message


I'm having issues sending Web Push Notifications to Edge. It works great in Chrome, Firefox, Safari, but not Edge.

I can get the endpoint, auth, and p256dh in the browser and save them to my database. When I try to use them in python with pywebpush library I always get error with HTTP status 400 and no body message. This makes it very hard to understand what the problem should be.

The endpoint that I get in Edge is always https://wns2-db5p.notify.windows.com/w. I'm not sure if this is correct since I read somewhere that Chromium-based browsers should all return https://fcm.googleapis.com/fcm. Does anyone know if that is true?

I noticed that Edge permission for notifications is a bit different for the user. I'm not really sure if this has anything to do with the validity of variables that the subscription returns. When I request permission, there is no popup, but just an icon at the end (right) of the browser's search bar. When clicking on it, you get the popup.

Edge permission popup after clicking the bell icon

After pressing allow, the notifications seem to be enabled and should be working since I get everything I need. But they don't.

Edge permissions after allowing notifications

I figured that maybe things aren't working on localhost, so I deployed my app, but it didn't help.

This is how I get endpoint, auth, and p256dh:

const subscription = await registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: urlBase64ToUint8Array('<my-public-vapid-key>'),
});
const subscriptionAsJson = subscription.toJSON();
const p256dh = subscriptionAsJson.keys?.p256dh;
const auth = subscriptionAsJson.keys?.auth;
const endpoint = subscriptionAsJson.endpoint;

function urlBase64ToUint8Array(base64String: string) {
  var padding = '='.repeat((4 - base64String.length % 4) % 4);
  var base64 = (base64String + padding)
      .replace(/\-/g, '+')
      .replace(/_/g, '/');
  
  var rawData = window.atob(base64);
  var outputArray = new Uint8Array(rawData.length);
  
  for (var i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

Here is also my code for sending the notifications in Python:

vapid_claims = settings.VAPID_CLAIMS
parsed_endpoint = urlparse(device.notification_endpoint)
webpush(
    subscription_info={
        "endpoint": device.notification_endpoint,
        "keys": {
            "p256dh": device.p256dh,
            "auth": device.auth,
        }
    },
    data=data,
    vapid_private_key=settings.VAPID_PRIVATE_KEY,
    vapid_claims={
        "sub": vapid_claims["sub"],
        "exp": vapid_claims["exp"],
        "aud": f"{parsed_endpoint.scheme}://{parsed_endpoint.netloc}",
    },
)

I'm using Django and this is how my relevant code in setting.py looks like:

VAPID_PUBLIC_KEY = os.getenv("VAPID_PUBLIC_KEY")
VAPID_PRIVATE_KEY = os.getenv("VAPID_PRIVATE_KEY")
VAPID_CLAIMS = {
    "sub": "mailto:<my-email>",
    "exp": 60,
}

I also tried sending notifications without setting claims since it works with other browsers, but it this case I get 401 error.


Solution

  • You seem to forget about setting the ttl, which is required. According to this thread, the 400 error was caused by not setting ttl and it seems to only affect Microsoft Edge.