A Manifest V3 browser extension that imports an already-authenticated WhatsApp Web session into your app, so you can pair a passkey-locked WhatsApp account with a whatsmeow client.
Passkey-locked accounts cannot be paired by driving QR from a headless client -
the server requires a WebAuthn assertion from the owner's own authenticator.
This extension lets the owner authenticate web.whatsapp.com natively (with
their passkey), then extracts that session and hands it to your backend for
conversion + import into whatsmeow. No re-pairing, no headless bypass.
Full end-to-end guide (whatsmeow + backend + converter + UI + this extension):
docs/WHATSMEOW-IMPLEMENTATION.md.
What this extension does
Opens web.whatsapp.com in a background tab, forces passkey mode, lets the owner
complete the native passkey flow (and 2FA PIN if any), waits for a complete and
stable session, dumps it, POSTs it to a signed one-time URL your app
provides, then wipes the WhatsApp Web session and closes the tab.
It integrates with any frontend through a small window.postMessage
protocol and with any backend through a single POST of the dump. See the
protocol in the guide.
Quick start
npm install
npm run build # -> dist/ (unpacked extension)
- Edit
manifest.config.tsand setAPP_HOSTSto the origin(s) where your web app runs (addhttp://localhost/*for local dev). Mirror the same list inAPP_HOST_PATTERNSinsrc/background/index.ts. npm run build.- Load it in Chrome:
chrome://extensions-> enable Developer mode -> Load unpacked -> select thedist/folder.
Package a signed .crx with npm run pack (generate key.pem first, keep it
private, never commit it).
Integration in one minute
Your app page, once a connection reports it needs a passkey:
// 1. detect the extension
window.addEventListener('message', (e) => {
if (e.data?.source === 'wa-passkey-connector' && e.data.type === 'CONNECTOR_READY') {
/* installed */
}
});
window.postMessage({ target: 'wa-passkey-connector', type: 'PING' }, '*');
// 2. start the flow with a signed one-time upload URL from your backend
const { url } = await fetch('/import-url', { method: 'POST' }).then((r) => r.json());
window.postMessage({ target: 'wa-passkey-connector', type: 'START_PASSKEY_IMPORT', url }, '*');
The extension replies with EXISTING_SESSION (needs consent), IMPORT_SENT, or
IMPORT_ERROR. Full message table in the guide.
Permissions
scripting, tabs, activeTab, storage, browsingData (used only to log out
web.whatsapp.com on the user's browser, with consent / after import), plus
host_permissions for web.whatsapp.com and your app host(s).
Tech
React 18 + Tailwind + Vite + @crxjs/vite-plugin. Neutral styling - restyle the
popup and replace the placeholder icons in public/icons/ with your own.
Caveats
This automates WhatsApp Web and relocates a session; it may violate WhatsApp's Terms of Service and browser-extension store policies. Always obtain the account owner's explicit consent, and prefer private/unlisted or enterprise distribution over a public store listing. Session dumps are impersonation-grade - handle them as secrets end to end.
Comments