Control model: Decide who holds the access
This is one of the most important architectural decisions you’ll make: who is in control of the wallets you create in your app. WIth Turnkey embedded wallets, each wallet is created in a segregated sub-organization. You can configure who has access to resources in that sub-org at the time of creation. Turnkey offers a wide spectrum of options here, from fully user-controlled to fully app-controlled and everything in between.- Fully user-controlled: Only the user can authorize actions. Your backend has zero access. This option is best for personal wallets or any use case or audience where self-custody is important.
- Fully app-controlled: Your backend holds the authenticators used to authorize actions on behalf of the user. Simple UX and no restrictions on when or how actions are triggered, useful for things like limit orders or automated flows.
- Delegated access: The user controls the wallet, but your backend is granted narrow signing permissions via Turnkey’s policy engine. Ideal for transaction automation without taking on full control.
- Shared custody: Both the user and your backend (or, the “co-signer) hold authenticators, and actions require approval from both. Accomplished via root quorum settings, like a 2-of-2 signing requirement, this setup can offer improved security depending on the level of independent validation done at the co-signer level.
Authentication: Decide how users access their wallets
Another key design choice is how users will authenticate to authorize actions. Every API request to Turnkey must include a signature, or stamp, over the POST body – that means every request to Turnkey needs to be authorized by a valid authenticator. Turnkey supports a range of authentication methods that can be enabled individually or in combination. You can configure which methods are allowed when getting started, and can always enable more options later as your product evolves.- Passkeys: WebAuthn-based authentication using device biometrics or security keys. Provides the strongest combination of security and UX when supported by the user’s browser and device.
- Email (magic link or OTP): Passwordless login using a one-time link or code sent to the user’s email. Ubiquitous, familiar, and often the easiest option for onboarding.
- Social login (OAuth): Sign in with providers like Google or Apple. Smooth UX and fast setup for users already logged into those ecosystems. Requires OIDC configuration.
- SMS (OTP): Login via a code sent by text message. Convenient in some markets but generally less secure due to SIM-swap risk.
- Multiple methods: You can enable multiple authenticators per user — for example, allowing passkey + email fallback, or social login + SMS recovery. This can improve account recovery or accessibility across devices.
Session handling: Decide how to manage session credentials
In Turnkey, sessions are just asymmetric key pairs held client-side that can be used to authorize actions. Once a user signs in, they can take multiple actions like viewing balances or signing transactions without re-authenticating each time. When designing your session approach, there are two key decisions to make: where sessions are stored, and how long they last. StorageTurnkey supports multiple storage approaches for session credentials, each with tradeoffs depending on platform and use case. IndexedDB session (web only): For web apps that want stronger session persistence without relying on iframes or exposing credentials to your app’s JavaScript runtime, Turnkey supports using the SubtleCrypto API to generate unextractable asymmetric key pairs and store them securely in the browser’s IndexedDB. This approach enables long-lived, client-held sessions that survive page reloads, tab closures, and even browser restarts - without ever exposing the private key to your JavaScript code. Turnkey’s SDK provides helpers to:
- Create a new session by generating a P-256 key pair via
crypto.subtle.generateKey()
- Sign requests
- Store and retrieve the key using IndexedDB under a given session ID
- Abstractions built on top of the
IndexedDBStamper
that simplify authentication flows
IndexedDbClient
for full e2e authentication flows.
Iframe-based session: Turnkey hosts a secure iframe at https://auth.turnkey.com which can be used to store the session credential
used to authorize actions, without exposing those credentials to your app. This method is secure and browser-isolated, but:
- Sessions last only as long as the iframe persists
- iOS aggressively clears iframe storage, making it less reliable on mobile
- React Native does not support iframes
Session credentials are time-bound and expire after the duration you specify. This is set via the expirationSeconds parameter when the session is created. The default is 900 seconds (15 minutes), but you can configure this to suit your needs. To read more about sessions and how to manage them, head to the Sessions Overview page.