Sub-Organizations as end-user controlled wallets
In this example wallet implementation, you will create a segregated sub-organization for each end-user, and leverage passkeys as cryptographic proof of ownership to ensure only the end-user has the ability to approve signing. Your application will construct transactions on behalf of the end-user, and then surface the relevant Turnkey activity request client-side for end-user approval. Note that Turnkey is not a customer authentication platform. This gives you the flexibility to create the user experience you envision. Typically, Turnkey integrators implement their own standard end-user authentication flows for login, then employ passkeys behind that login for transaction signing. If you’d like to see a live example, head over to our ✨Demo Embedded Wallet✨, and follow along with the code here.Before you start
Make sure you’ve set up your primary Turnkey organization with at least one API user for programmatic user onboarding. Check out our Quickstart guide if you need help getting started.Step 1: Create a sub-organization
After the end-user is logged in, your application prompts the user for passkey creation on the application domain. Our JavaScript SDK has a helper for this:getWebAuthnAttestation
. See this example.
Your application then uses an API-only user to create a new sub-organization on behalf of the end-user with a CREATE_SUB_ORGANIZATION
activity. In the example below, the new sub-organization has one root user controlled by the end user’s passkey, and an associated Ethereum wallet:
CREATE_SUB_ORGANIZATION_V4
activity here.
Step 2: Wallet creation
While the first wallet creation is already done (ourCREATE_SUB_ORGANIZATION
activity accepts a wallet
parameter!), your end-users can derive more accounts or create more wallets after the fact by using their passkeys to sign a CREATE_WALLET
activity.
We’ve abstracted getting WebAuthn signatures and creating signed Turnkey requests behind typed methods (e.g. createWallet
).
Our TurnkeyClient
(from @turnkey/http
) can be initialized with a WebauthnStamper
(from @turnkey/webauthn-stamper
):
signedRequest
, which contain all the components needed to forward it to Turnkey: URL, body, and a stamp header (with name and value properties). Use httpClient.stampCreateWallet
to get a signed request. Your backend server can then proxy it to Turnkey.
Next, we can derive additional accounts (addresses) given a single HD wallet. The shape of the request is as follows:
Step 3: Transaction signing
The end-user must provide a signature over eachSIGN_TRANSACTION
activity with their passkey. In your application, a user action (for example tapping a “Withdraw Rewards” button) might trigger the flow. The details of this transaction should be presented to the user for confirmation, followed by a passkey prompt to sign the Turnkey activity. An activity to sign a transaction looks like the following:
Sub-Organizations as custodial wallets
Most of the steps outlined in the previous section remain unchanged: applications creating custodial wallets should still create segregated sub-organizations for their end-users to avoid limits (we currently have a maximum of 100 users per organization, whereas an organization can have unlimited sub-organizations). The main difference is in the Root Quorum settings: upon creating a new sub-organization, your business’s API key is used to bootstrap each end-user organization. TheCREATE_SUB_ORGANIZATION_V4
activity becomes:
Sub-Organizations as shared Wallets
For the sake of completeness: it is possible to create “shared custody” wallets with the sub-organization primitive. To do this, an application would setup sub-organizations with the following settings:- Root quorum threshold: 2
-
Root users:
- 1 user representing the end-user (with their Passkey as an authenticator)
- 1 user representing the business (with an API key attached)