Skip to content
Back to skills

Push Notifications

ASecurity

Web Push — service worker, VAPID, permission UX, subscriptions, browser support, security.

  • 6 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
ai-agentsapifrontendbackendsecurity

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 5, 2026

npx -y skills add Dev-Toolbelt/dev-team-agents --skill push-notifications --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Push Notifications?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Push Notifications
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dev-toolbelt-push-notifications/badge)](https://www.skillsdirectory.com/skills/dev-toolbelt-push-notifications)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: push-notifications
description: Web Push — service worker, VAPID, permission UX, subscriptions, browser support, security.
---

## Decision Table — What to Load

| Task | Load |
|------|------|
| Cross-browser support, Safari quirks, iOS PWA, framework integration | `references/browser-compatibility.md` |
| SW registration, permission flow, subscribing, push/click event handlers | `references/service-worker.md` |
| VAPID key generation, subscription storage, expiry, server-side sending | `references/subscription-management.md` |

Load only the reference(s) relevant to the current task.

---

## Core Rules (apply without loading references)

- **HTTPS required** — service workers do not register on plain HTTP (`localhost` is the only exception)
- **Never request permission on page load** — always tie the prompt to an explicit user action
- **`userVisibleOnly: true`** is mandatory in `pushManager.subscribe()` — Chrome rejects without it
- **VAPID private key is server-side only** — never in the frontend bundle
- **iOS push = PWA only** — does not work in the Safari browser tab; show "Add to Home Screen" first
- **Delete 410/404 subscriptions immediately** — they are permanently invalid
- **Design for `title` + `body` + `icon` only** — `actions`, `image`, `badge`, `vibrate` are progressive enhancement

---

## Prerequisites

1. HTTPS (or `localhost`)
2. Registered and active service worker
3. VAPID key pair generated and stored (`npx web-push generate-vapid-keys`)

---

## Quick-Start Flow

1. Register SW on app load (do not prompt yet)
2. On user action → check `Notification.permission` → show double opt-in UI → call `Notification.requestPermission()`
3. On grant → `pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: <vapid-public> })`
4. POST subscription object to backend → store per authenticated user
5. SW handles `push` event → `showNotification()`
6. SW handles `notificationclick` → focus or open the target URL
7. SW handles `pushsubscriptionchange` → resubscribe and update backend
8. Backend: delete subscriptions on 410/404; retry on 429 with backoff

---

## Security Checklist

- [ ] VAPID private key is server-side only — never in the frontend bundle
- [ ] `applicationServerKey` (public) is safe to expose in the bundle
- [ ] Subscription endpoints stored with the authenticated user — never accessible cross-user
- [ ] Push payload is validated on the server before sending
- [ ] No PII in the push payload — notification body is visible on the lock screen
- [ ] Backend deletes 410 subscriptions immediately to avoid endpoint enumeration
- [ ] HTTPS enforced end-to-end (required by spec)

---

## Implementation Checklist

- [ ] Feature detection — push opt-in UI hidden when not supported
- [ ] iOS PWA detection — "Add to Home Screen" prompt shown before permission request on iOS
- [ ] Permission requested only on explicit user action (never on page load)
- [ ] `pushsubscriptionchange` event handled in SW
- [ ] Subscription sent to backend and stored per authenticated user
- [ ] `notificationclick` opens correct URL and focuses existing tab if open
- [ ] Notifications work without `actions`/`image` (progressive enhancement)
- [ ] Backend deletes 410/404 subscriptions
- [ ] VAPID private key not in frontend bundle
- [ ] Safari macOS: `push_server_url` in manifest
- [ ] iOS: push tested in installed PWA, not browser tab
- [ ] No PII in notification body or payload

Files in this skill

  • SKILL.md3.4 KB
  • references/browser-compatibility.md2.9 KB
  • references/service-worker.md5.2 KB
  • references/subscription-management.md2.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.