Summary
Web Push never arrives on iOS/Safari (installed PWA) while Chrome/Android work.
Root cause
The VAPID sub claim is hard-coded to mailto:noreply@meshcore.local (app/push/manager.py, app/routers/push.py). Apple's APNs rejects that JWT with 403 {"reason":"BadJwtToken"} because .local is a reserved TLD. Google FCM doesn't validate sub strictly, so Chrome/Android are unaffected — which makes the bug look platform-specific.
Verified against a live iOS subscription:
sub = mailto:noreply@meshcore.local -> 403 BadJwtToken
sub = mailto:noreply@example.com -> 201 Created
sub = mailto:<real address> -> 201 Created (delivered)
Server, VAPID keys, outbound networking, and clock are all fine.
Proposed fix
I'm opening this issue for discussion per CONTRIBUTING. Since this is a small, additive fix rather than a large feature, I've gone ahead and submitted the PR as well so it's ready to review.
The simplest, lowest-risk fix is to add a MESHCORE_VAPID_SUBJECT env var and keep the current default unchanged — purely additive, no behavior change unless an operator sets it. iOS operators would set it to a real mailto:.
That said, I'm open to your preference on the default. We could change it to a real address so push works on iOS out of the box without configuration — either something generic like mailto:noreply@example.com, or mailto:noreply@meshcore.io. The meshcore.io option isn't really my call to make, so I'll defer to you on whether that's appropriate. Happy to adjust the PR to whatever you decide.
**Summary**
Web Push never arrives on iOS/Safari (installed PWA) while Chrome/Android work.
**Root cause**
The VAPID `sub` claim is hard-coded to `mailto:noreply@meshcore.local` (`app/push/manager.py`, `app/routers/push.py`). Apple's APNs rejects that JWT with `403 {"reason":"BadJwtToken"}` because `.local` is a reserved TLD. Google FCM doesn't validate `sub` strictly, so Chrome/Android are unaffected — which makes the bug look platform-specific.
Verified against a live iOS subscription:
```
sub = mailto:noreply@meshcore.local -> 403 BadJwtToken
sub = mailto:noreply@example.com -> 201 Created
sub = mailto:<real address> -> 201 Created (delivered)
```
Server, VAPID keys, outbound networking, and clock are all fine.
**Proposed fix**
I'm opening this issue for discussion per CONTRIBUTING. Since this is a small, additive fix rather than a large feature, I've gone ahead and submitted the PR as well so it's ready to review.
The simplest, lowest-risk fix is to add a `MESHCORE_VAPID_SUBJECT` env var and keep the current default unchanged — purely additive, no behavior change unless an operator sets it. iOS operators would set it to a real `mailto:`.
That said, I'm open to your preference on the default. We could change it to a real address so push works on iOS out of the box without configuration — either something generic like `mailto:noreply@example.com`, or `mailto:noreply@meshcore.io`. The meshcore.io option isn't really my call to make, so I'll defer to you on whether that's appropriate. Happy to adjust the PR to whatever you decide.
<!-- github-sync-id:4670094235 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Web Push never arrives on iOS/Safari (installed PWA) while Chrome/Android work.
Root cause
The VAPID
subclaim is hard-coded tomailto:noreply@meshcore.local(app/push/manager.py,app/routers/push.py). Apple's APNs rejects that JWT with403 {"reason":"BadJwtToken"}because.localis a reserved TLD. Google FCM doesn't validatesubstrictly, so Chrome/Android are unaffected — which makes the bug look platform-specific.Verified against a live iOS subscription:
Server, VAPID keys, outbound networking, and clock are all fine.
Proposed fix
I'm opening this issue for discussion per CONTRIBUTING. Since this is a small, additive fix rather than a large feature, I've gone ahead and submitted the PR as well so it's ready to review.
The simplest, lowest-risk fix is to add a
MESHCORE_VAPID_SUBJECTenv var and keep the current default unchanged — purely additive, no behavior change unless an operator sets it. iOS operators would set it to a realmailto:.That said, I'm open to your preference on the default. We could change it to a real address so push works on iOS out of the box without configuration — either something generic like
mailto:noreply@example.com, ormailto:noreply@meshcore.io. The meshcore.io option isn't really my call to make, so I'll defer to you on whether that's appropriate. Happy to adjust the PR to whatever you decide.