How to Generate VAPID Keys with web-push, Node or OpenSSL
Generate the VAPID key pair that authenticates your push server to browser push services — using the web-push CLI, Node's crypto module, or OpenSSL.
ProfitTool Team
Developer Tools
What VAPID Keys Are
VAPID (Voluntary Application Server Identification) is an RFC 8292 standard for authenticating push notification servers. Instead of sharing an API key with each browser push service, your server proves its identity using a public/private key pair.
The public key is shared with the browser when a user subscribes to push notifications. The private key is kept secret on your server and used to sign JWT tokens sent to the push service.
Generating VAPID Keys
Using web-push (Node.js)
npm install web-push
npx web-push generate-vapid-keysOutput:
Public Key: BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U
Private Key: UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTWKGKlsUsing openssl (any platform)
# Generate P-256 private key
openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem
# Extract public key
openssl ec -in vapid_private.pem -pubout -out vapid_public.pem
# Convert to raw base64url format (needed for VAPID)
openssl ec -in vapid_private.pem -noout -text 2>&1 | grep -A 3 "priv:" | tail -3 | tr -d ' :
'Environment Variable Setup
VAPID_PUBLIC_KEY=BEl62iUYgUivxIkv69yViEuiBIa...
VAPID_PRIVATE_KEY=UUxI4O8-FbRouAevSmBQ6o18hgE4...
VAPID_SUBJECT=mailto:hello@yourdomain.comClient-Side Subscription
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
});
// Send subscription to your server
await fetch('/api/subscribe', {
method: 'POST',
body: JSON.stringify(subscription)
});Key Security Notes
- Generate new VAPID keys for each application
- Never expose the private key in client-side code
- Store keys in environment variables, never in source code
- Keys are long-lived — rotation requires re-subscribing all users
What the Keys Actually Sign
The key pair is not sent to the push service on every request. Instead, your server builds a short-lived JWT, signs it with the private key using ES256, and sends both the token and the public key in one header:
Authorization: vapid t=<signed JWT>, k=<base64url public key>RFC 8292 fixes three claims in that token. aud must be the origin of the push service you are calling (for example https://fcm.googleapis.com), sub must be a mailto: or https: contact URL so the push service can reach you, and exp must be no more than 24 hours in the future. A push service rejects a token whose exp sits further out than that — the most common cause of a 401 when the keys themselves are correct.
If a push request is failing, paste the t= value into the JWT Decoder to read the header and payload, or the JWT Claims Inspector to see the expiry as a countdown rather than a Unix timestamp. Note that VAPID keys and JWT segments are base64url, not standard Base64 — the Base64URL Encoder & Decoder handles the - and _ alphabet that a plain Base64 tool will reject.
For the claim rules themselves see JWT Expiration Explained, and for how the token is structured, What Is a JWT?.
ProfitTool Team
Developer ToolsWritten and maintained by the ProfitTool team. Where an article references a ProfitTool utility, the behaviour described is the behaviour of the tool on this site — you can open it and check the output yourself.
Try the Interactive Tools Mentioned
Free to use with no ProfitTool signup. Data handling varies by tool.
More from the Knowledge Hub
What Is a Service Worker? PWA Caching and Offline Mode Explained
Service workers are scripts that run in the background, separate from your web page. They power offline mode, background sync and push notifications in Progressive Web Apps.
Developer ToolsHow to Decode a JWT Token (Without a Library)
You can decode a JWT token in any language using nothing but base64url decoding and JSON parsing. Here is how to do it in JavaScript, Python and the browser.
Developer ToolsJWT Expiration Explained: exp, iat and nbf Claims
How JWT time claims work — exp, iat and nbf — plus clock skew tolerance, choosing a token lifetime, refresh-token rotation and the revocation gap.