In building crypto products, balancing trade-offs between user accessibility and security is a constant challenge. Developers building wallets for end users are very familiar with this dilemma. To help fill this gap, Turnkey added support for passkeys as an authenticator; many developers building on Turnkey have opted to implement passkeys as the primary authentication method because they’re quick to use, secure, and generally easy to recover.
But in crypto, “generally easy to recover” isn’t good enough. Passkeys are a great new tool for wallet authentication, but they’re not infallible. Users who are new to passkeys may fail to back them up, in which case, if they lose their device, they also lose their crypto. The feedback from dapp developers building on Turnkey was unambiguous; their end users want an additional recovery method as a safety net. Today, email is the MVP recovery method: it’s ubiquitous, familiar, low-friction, and secure enough for most users.
Engineering a secure solution
The task was clear but challenging: design an email recovery path for these end users to access their non-custodial wallets, without an existing authenticator and without unacceptable compromises on security. This meant devising a system where no party involved in facilitating the email recovery flow — be it Turnkey, dapp developers, the email delivery service, or the email provider — can intercept the recovery credential.
A core requirement in Turnkey’s architecture is that every action must be cryptographically authenticated (more on that here). This raises a big question: How can we facilitate the creation of a new authenticator in the absence of an existing one?
Hard to understand, easy to use
While there are some intricate backend processes and fancy cryptography at play that we'll explain in the next section, the user experience is simple. The end user will simply receive an email, click a link or copy and paste a code into the app’s recovery screen, and add a new authenticator. Done! Now, for the details:
How it works
To engineer this new secure recovery solution, we introduced two new activities: INIT_USER_EMAIL_RECOVERY and RECOVER_USER.
When an end user initiates recovery through an application integrated with Turnkey, a recovery UI is presented and the application frontend uses @turnkey/iframe-stamper to create a new iframe element and open it in the background. This iframe, hosted on Turnkey’s domain, generates a new encryption target key and saves it securely in the end user’s localStorage where only scripts running on recovery.turnkey.com have access to it.
The user is then prompted to enter their email address into the recovery form. This action triggers a request, initiating the recovery process using the user's email and the iframe's public key. The application’s backend identifies the correct Turnkey sub-organization ID and creates a new INIT_USER_EMAIL_RECOVERY activity, securing it with our API key.
Upon successful completion of this initial activity, the user is prompted with instructions to proceed with the recovery using a code sent to the email associated with that user.
This code, once entered into the form, is injected into the iframe and decrypted securely.
The final step involves the user creating a new passkey. This is where our SDK comes into play, enabling the signing and submission of the RECOVER_USER
activity using the credential stored in the iframe. The successful completion of this activity marks the end of the recovery process.
Itching to dig deeper? You can learn more about how email recovery works here, or jump to our guide on implementing for end users here. Or, go try it out for yourself at https://wallet.tx.xyz/.