| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Add opt-in support for WhatsApp's passkey (Shortcake/CRSC) companion-linking flow, implemented on top of Baileys' public API without forking it. A browser helper extension performs the WebAuthn assertion; the ceremony is driven via public /passkey-ceremony endpoints and exposed through connectionState. Gated behind PASSKEY_CEREMONY_ENABLED (default off) since a malformed IQ can get the number banned. Requires PASSKEY_PUBLIC_URL reachable by the browser.
There was a problem hiding this comment.
Sorry @mateus2001ferreira, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
Sorry, something went wrong.
✅ Passkey linking working with 1Password after additional fixesHi! I would like to share the results of my tests with the new Passkey Companion Linking implementation from this PR. After some debugging and modifications, I was able to successfully connect my existing Evolution API instance to WhatsApp using a passkey stored in 1Password.
My original problemMy Evolution API installation was working normally before WhatsApp started requiring passkey authentication during companion-device linking. The QR Code was generated normally. After scanning it with WhatsApp, however, WhatsApp requested passkey/device authentication and the Evolution API instance never completed the connection. I was originally using:
Because my project already depends on the original Evolution API database structure and integrations, migrating everything to Evolution GO would require significant changes. Testing Evolution GO firstI installed Evolution GO to understand how the new authentication flow was supposed to work. Evolution GO detected that WhatsApp required a passkey and generated a URL similar to: https://web.whatsapp.com/#wapk=... It also instructed me to install the official Evolution Passkey Helper Chrome extension. However, I had problems completing the authentication with my setup and 1Password. This gave us an important reference for how the passkey flow was intended to work. Creating an alternative Passkey HelperUsing the Evolution GO Passkey Helper as a reference, I asked ChatGPT to analyze how it worked and create an alternative helper specifically for my Evolution API installation. The architecture that finally worked was:
This was important because it allowed the WebAuthn request to be correctly detected by the 1Password Chrome extension. After this change, 1Password opened normally and allowed me to authenticate using my existing WhatsApp passkey. Evolution Manager does not display the Passkey URLThere is also an important UI problem. When I perform the pairing through the Evolution Manager web interface, the QR Code appears normally. After scanning the QR Code and WhatsApp requesting the passkey, the Evolution Manager does not show the URL required to continue the authentication. Nothing appears in the web interface telling the user to open the Passkey Helper. The URL only appeared in the Evolution API server logs: [Passkey] prologue_request received. Open in the browser helper: https://web.whatsapp.com/#wapk=... Because of this, I had to:
It would be very useful if Evolution Manager automatically displayed a button/link using passkeyOpenUrl whenever a passkey ceremony is requested. For a normal user who does not have access to the server terminal, the current flow is very difficult to discover. First problem after successful 1Password authenticationAfter getting WebAuthn/1Password authentication working, Evolution API successfully progressed further. The helper displayed the confirmation code. However, when confirming it, Evolution API returned: ERROR [PasskeyController] confirm: ceremony has no encryption key yet At the same time, I noticed that Evolution API continued generating/rotating QR Codes even though the passkey ceremony was already active. For example: qrcodeCount: 16 qrcodeCount: 17 qrcodeCount: 18 qrcodeCount: 19 The passkey ceremony had already started, but QR processing continued. hasActiveByInstance() already existedWhile analyzing the PR source code, we noticed that the passkey ceremony store already contains: passkeyCeremonyStore.hasActiveByInstance(instanceId) However, it did not appear to be used by the normal WhatsApp QR/reconnection handling. Our hypothesis was that the connection/QR lifecycle could change while the passkey ceremony still depended on cryptographic state kept in memory. That would explain why the confirmation UI existed but the controller later reported: ceremony has no encryption key yet Fix 1 — Stop QR rotation while Passkey Ceremony is activeWe modified connectionUpdate() to detect an active passkey ceremony. Conceptually, the change was: const passkeyActive =
process.env.PASSKEY_CEREMONY_ENABLED === 'true' &&
passkeyCeremonyStore.hasActiveByInstance(this.instanceId);
if (qr && passkeyActive) {
this.logger.log(
'[Passkey] ceremony active - ignoring QR rotation to preserve cryptographic state',
);
}
if (qr && !passkeyActive) {
// existing QR processing
}After this modification the server correctly reported: [Passkey] ceremony active - ignoring QR rotation to preserve cryptographic state This prevented QR rotation from interfering with the active ceremony. The previous ceremony has no encryption key yet behavior was no longer the main blocker. However, pairing still did not finish. Second problem — WhatsApp/Baileys stream error 515The next important event in the logs was: stream:error code="515" Initially, we also prevented Evolution API from reconnecting while the passkey ceremony was active. The server reported: [Passkey] ceremony active - suppressing reconnect to preserve cryptographic state This successfully protected the ceremony state. But there was another problem: the WhatsApp connection never completed. The browser remained processing and the device was not added to WhatsApp's linked devices. Important discovery — reconnect must depend on the Passkey stageWe then changed the logic so reconnect behavior depends on the current passkey ceremony stage. During these stages:
the reconnect should be suppressed so that the cryptographic state is preserved. But after:
the reconnect must be allowed. This was the key change that finally completed the pairing. Fix 2 — Stage-aware reconnectThe working logic is currently: const passkeyState =
process.env.PASSKEY_CEREMONY_ENABLED === 'true'
? passkeyCeremonyStore.stateByInstance(this.instanceId)?.state.stage
: undefined;
const passkeyInProgress =
passkeyState === 'challenge' ||
passkeyState === 'awaiting_confirmation' ||
passkeyState === 'confirmation';
const shouldReconnect =
!passkeyInProgress &&
!codesToNotReconnect.includes(statusCode);
if (passkeyInProgress) {
this.logger.log(
`[Passkey] ceremony stage=${passkeyState} - suppressing reconnect to preserve cryptographic state`,
);
return;
}
if (passkeyState === 'confirmed') {
this.logger.log(
'[Passkey] ceremony confirmed - allowing reconnect to complete WhatsApp pairing',
);
}
if (shouldReconnect) {
await this.connectToWhatsapp(this.phoneNumber);
}🎉 Successful resultAfter applying both changes, I performed a completely new pairing attempt. The server received: [Passkey] prologue_request received I opened the generated #wapk URL in Chrome. Our modified Passkey Helper triggered WebAuthn in the WhatsApp Web MAIN world. 1Password opened correctly. I authenticated using my WhatsApp passkey. The ceremony progressed. WhatsApp/Baileys then returned: stream:error code="515" But this time Evolution API detected that the ceremony was already confirmed and logged: [Passkey] ceremony confirmed - allowing reconnect to complete WhatsApp pairing Immediately afterwards: CONNECTED TO WHATSAPP And the instance successfully connected. I also tested the instance after pairing and message communication worked normally. Final working flowThe successful flow in my environment is: Evolution Manager generates QR
↓
WhatsApp scans QR
↓
WhatsApp requests Passkey
↓
passkey_prologue_request
↓
Evolution creates Passkey Ceremony
↓
#wapk URL generated
↓
Open URL in Chrome
↓
Passkey Helper executes WebAuthn
inside web.whatsapp.com MAIN world
↓
1Password detects the request
↓
Authenticate WhatsApp Passkey
↓
Signed WebAuthn assertion returned
to Evolution API
↓
Preserve Passkey cryptographic state
↓
Ignore QR rotation during ceremony
↓
Do not reconnect prematurely
↓
Passkey ceremony confirmed
↓
WhatsApp/Baileys stream 515
↓
Reconnect is now allowed
↓
CONNECTED TO WHATSAPP
↓
Messages working normally
Suggested improvementsBased on my tests, I believe there are three areas worth reviewing. 1. Display passkeyOpenUrl in Evolution ManagerThe backend already generates the URL, but I could only see it in the server logs. When WhatsApp requests a passkey, Evolution Manager should display something like: "WhatsApp requires Passkey authentication — Open Passkey Helper" using the generated passkeyOpenUrl. This would make the feature usable without requiring terminal/server access. 2. Protect the active Passkey Ceremony from QR rotationWhen a passkey ceremony is active, new QR updates should probably not replace/interfere with the connection state required by the ceremony. Using passkeyCeremonyStore.hasActiveByInstance() to detect this solved the problem in my environment. 3. Make reconnect Passkey-stage awareCompletely disabling reconnect while a passkey ceremony exists is not sufficient. In my test: challenge / awaiting_confirmation / confirmation needed the cryptographic state to be preserved. But after: confirmed Evolution needed to allow the reconnect after the WhatsApp/Baileys 515 event. This final reconnect is what actually completed the WhatsApp connection. Test environment
About the custom extensionI also have the modified Chrome Passkey Helper that worked with this setup. It was created after analyzing the Evolution GO Passkey Helper and adapting the flow so WebAuthn runs in the WhatsApp Web MAIN world and can be handled by 1Password. I can share the extension source code if it is useful for this PR. Before publishing it, I would prefer that someone from the project reviews the implementation, since, as mentioned above, I am not a developer and the extension/code changes were created with ChatGPT's assistance. I can also provide the exact git diff of the Evolution API modifications that are currently working on my server. I hope these test results help with the Passkey implementation. Thanks for working on this feature! I am also attaching the generic version of the Chrome Passkey Helper used in my successful test. It contains no private server information or credentials and dynamically reads the Evolution API URL and ceremony token from the #wapk payload. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Description
Adds opt-in support for WhatsApp's passkey (Shortcake/CRSC) companion-linking flow, which some numbers now require when linking a device. Implemented on top of Baileys' public API — no fork or patch of Baileys needed.
How it works:
Gated behind PASSKEY_CEREMONY_ENABLED=true (default off), since a malformed IQ can get a number banned. Also requires:
Crypto is an independent reimplementation of whatsmeow's pair-passkey.go (MPL-2.0); no code copied. No dependency changes (works on the current Baileys 7.0.0-rc.9).
Type of Change
Checklist
Additional Notes
The feature ships a small browser helper extension (public/passkey-helper.zip) that performs the WebAuthn assertion. Happy to discuss whether shipping it in-repo, as source, or as a separate distribution is preferable. Also glad to add the two env vars to .env.example if the approach is accepted.