> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# VAPID keys for web push (Lovable, Supabase, Vercel)

> This guide merges the former split between “setup” and “Lovable” docs. Never commit real VAPID private keys or production key pairs to git. Use placeholders be…

**Last updated:** 2026-03-23\
**Related:** PF-10 notifications / push; `supabase/functions/send-push-notification`, `src/platform/notifications/hooks/usePushSubscription.ts`

This guide merges the former split between “setup” and “Lovable” docs. **Never commit real VAPID private keys or production key pairs to git.** Use placeholders below and store secrets only in Supabase Edge secrets and your host’s env UI.

***

## 1. Executive summary

Web push requires a **VAPID key pair** and **subject** (`mailto:` or `https:` URL). The **`send-push-notification`** Edge Function in this repo implements sending with **Deno’s Web Crypto APIs** (VAPID JWT signing and payload encryption) — **no Node `web-push` package in Edge**. If you add or replace server-side push logic, use a **Deno-compatible** Web Push library (for example `@negrel/webpush`) **or** call a **separate Node** service that uses `web-push`, invoked from the Edge Function. The client continues to expose only the **public** key via **`VITE_VAPID_PUBLIC_KEY`** (unchanged).

***

## 2. Generate keys

On a trusted machine (not committed to the repo):

```bash theme={null}
npx web-push generate-vapid-keys
```

This command uses the `web-push` **CLI** only to generate keys; it is not the Edge runtime library. Record **public key**, **private key**, and set **subject** to a contact the push service can use, for example `mailto:your-team@yourorg.org`.

Rotate keys annually or immediately if compromised. After rotation, users may need to re-subscribe.

***

## 3. Lovable / Supabase (server-side)

In Supabase (or Lovable secrets UI for the project), set Edge Function secrets for `send-push-notification`:

| Secret              | Value                | Notes                                              |
| ------------------- | -------------------- | -------------------------------------------------- |
| `VAPID_PUBLIC_KEY`  | `<your-public-key>`  | Same pair as client public key                     |
| `VAPID_PRIVATE_KEY` | `<your-private-key>` | **Server only** — never in the browser or `VITE_*` |
| `VAPID_SUBJECT`     | `mailto:...@...`     | Required contact                                   |

Deploy the edge function after setting secrets.

***

## 4. Vercel / local (client-side)

| Variable                | Value               | Where                                                        |
| ----------------------- | ------------------- | ------------------------------------------------------------ |
| `VITE_VAPID_PUBLIC_KEY` | `<your-public-key>` | Vercel env (all envs you use) and `.env.local` for local dev |

The private key must **not** appear here.

***

## 5. Implementation notes

* Edge: see `supabase/functions/send-push-notification/index.ts` — native Web Crypto (RFC 8292 / 8291), no third-party push dependency; logs may reference `web-push-native` as the provider label.
* Client: subscription flow in `usePushSubscription`; storage table `pf_push_subscriptions`.
* New or alternate server implementations: prefer Deno-compatible Web Push libraries or a Node sidecar (see executive summary), not the Node `web-push` module inside Edge unless you run it in a separate Node runtime.

***

## 6. Verification

1. `VAPID_*` secrets present in Supabase for the push function.
2. `import.meta.env.VITE_VAPID_PUBLIC_KEY` defined in the built client.
3. Subscribe from the app; confirm a row in `pf_push_subscriptions`.
4. Send a test push; confirm delivery and edge logs.

***

## 7. Security

* Private key: Supabase secrets only.
* **`pf_push_subscriptions`:** Rows can hold device subscription endpoints and keys, `user_id`, and metadata — in healthcare contexts this may be **PII or PHI-adjacent**. Treat the table as **sensitive**: rely on RLS and least-privilege access, Supabase encryption in transit and at rest, audit who can read or export rows, and **never log, document, or paste real tokens or subscription payloads** in issues or PRs (same discipline as the private key rule above).
* Enable secret scanning on the repository.
* Do not paste real keys into Markdown in pull requests.

***

## 8. Troubleshooting

| Symptom                            | Likely cause                     | Fix                                                    |
| ---------------------------------- | -------------------------------- | ------------------------------------------------------ |
| 503 “VAPID keys required”          | Missing Supabase secrets         | Set secrets and redeploy function                      |
| Client “public key not configured” | Missing `VITE_VAPID_PUBLIC_KEY`  | Add to Vercel / `.env.local` and rebuild               |
| 401/403 from push service          | Bad pair or wrong subject format | Regenerate pair; subject must be `mailto:` or `https:` |

***

## Related documentation

* [specs/pf/specs/PF-13-phases-6-7-8-implementation-plan.md](https://github.com/Encore-OS/encoreos/blob/development/specs/pf/specs/PF-13-phases-6-7-8-implementation-plan.md) (push phases)
* [docs/integrations/EDGE\_FUNCTIONS.md](/integrations/EDGE_FUNCTIONS)
* [docs/security/SECRETS\_MANAGEMENT.md](/security/SECRETS_MANAGEMENT)
* [docs/development/ENVIRONMENT\_VARIABLES.md](/development/ENVIRONMENT_VARIABLES)
* [notification-quick-wins.md](/pf/recommendations/notification-quick-wins)
* [PWA\_IOS\_PUSH\_NOTIFICATION\_REVIEW.md](/pf/recommendations/PWA_IOS_PUSH_NOTIFICATION_REVIEW)
