Skip to content

Chromium aesgcm/aes128gcm pushes are always refused with HTTP 400 #225

@stephanfuhrmanngesundde

Description

When using up-to-date Chromium browsers, endpoint URLs like https://jmt17.google.com/fcm/send/... return a HTTP 400 error.
Chrome and Edge use different webpush servers/endpoints are all ok.

Requests look like this:

POST https://jmt17.google.com/fcm/send/...
Accept-Encoding: aesgcm,deflate,gzip,x-gzip
Authorization: ...
Content-Encoding: aesgcm
Content-Type: application/octet-stream
Crypto-Key: dh=...;p256ecdsa=...
Encryption: salt=...
Topic: ...
TTL: 2592000
Urgency: normal
User-Agent: ...

The responses look like this:

HTTP/1.1 400 Bad Request

Content-Security-Policy-Report-Only: script-src 'none'; form-action 'none'; frame-src 'none'; report-uri https://csp.withgoogle.com/csp/goa-520bfc14_2
Content-Type: text/plain; charset=utf-8
Cross-Origin-Opener-Policy: same-origin, Vary: Sec-Fetch-Site, Vary: Sec-Fetch-Mode, Vary: Sec-Fetch-Dest
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN, X-Xss-Protection: 0
Date: Wed, 16 Jul 2025 09:32:23 GMT,
Content-Length: 13
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

bad request.

Unfortunately it's not telling much about the background.

When I'm removing both the Crypto-Key and the Encryption headers, I get from jmt17.google.com this info:

HTTP/1.1 403 Forbidden
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Length: 182
Content-Security-Policy-Report-Only: script-src 'none'; form-action 'none'; frame-src 'none'; report-uri https://csp.withgoogle.com/csp/goa-520bfc14_2
Content-Type: text/plain; charset=utf-8
Cross-Origin-Opener-Policy: same-origin
Date: Wed, 16 Jul 2025 09:44:24 GMT
Vary: Sec-Fetch-Site,Sec-Fetch-Mode,Sec-Fetch-Dest
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 0

permission denied: crypto-key header had no public application server key specified. crypto-key header should have the following format: p256ecdsa=base64(publicApplicationServerKey)

The webpush demo website https://simple-push-demo.vercel.app/ is actually working with a request like this (no headers besides Authorization needed for aes128gcm:

curl \
  "https://jmt17.google.com/fcm/send/..." \
  --request POST \
  --header "TTL: 60" \
  --header "Content-Encoding: aes128gcm" \
  --header "Authorization: vapid t=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ptdDE3Lmdvb2dsZS5jb20iLCJleHAiOjE3NTI3MDM2MjQsInN1YiI6Im1haWx0bzpzaW1wbGUtcHVzaC1kZW1vQGdhdW50ZmFjZS5jby51ayJ9.t-B41LwJf5jab99aWu-TwKC9cdi5aJwJHj5dTVpGxCUPDzAJsunjHHgdwAxzG4_6HEXK_UwEzmlCyiAwmBJHSg, k=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo" \
  --data-binary @payload.bin

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions