Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions category/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,14 @@ holistic security model in-depth, and speaks to our vision for building verifiab
Overview of Turnkey's responsible disclosure program
</Card>

<Card
title="IP Allowlisting"
href="/security/ip-allowlisting"
icon="file-lines"
iconType="solid"
horizontal
>
Overview of Turnkey's responsible disclosure program
</Card>

</CardGroup>
22 changes: 11 additions & 11 deletions concepts/users/best-practices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@ description: "This page describes some best practices to consider as you set up

## Managing users

**Enforce a security policy of least privilege for your users**
Users on Turnkey should have the minimum required privilege to accomplish their job. When setting up users, consider this for their access type and policies that will grant the user permissions.
**Enforce a security policy of least privilege for your users** Users on Turnkey should have the minimum required privilege to accomplish their job. When setting up users, consider this for their access type and policies that will grant the user permissions.

**Use user tags to create groups of users with equal permissions**
Referencing user tags in policies instead of individual users allows for clearer management of permissions.
**Use user tags to create groups of users with equal permissions** Referencing user tags in policies instead of individual users allows for clearer management of permissions.

**When creating new users, consider verifying onboarding before adding tags**
When inviting a web user to your Turnkey organization, you should consider real-life verification to confirm that they have onboarded correctly before granting that user permissions via tags. Granting tags prior to verification could provide an attacker permissions in your Turnkey organization if they are able to access the signup link.
**When creating new users, consider verifying onboarding before adding tags** When inviting a web user to your Turnkey organization, you should consider real-life verification to confirm that they have onboarded correctly before granting that user permissions via tags. Granting tags prior to verification could provide an attacker permissions in your Turnkey organization if they are able to access the signup link.

**Regularly review and remove unused users, user tags, and policies**
If a user is unused or the user has left your company, you should remove them from your Turnkey organization to avoid compromise.
**Regularly review and remove unused users, user tags, and policies** If a user is unused or the user has left your company, you should remove them from your Turnkey organization to avoid compromise.

**Attach multiple authenticators to web users**

Expand All @@ -33,6 +29,10 @@ This reduces the ways that a hacker could acquire your API key. Our SDKs and CLI

This allows you to isolate permissions and differentiate activities between those applications. In the case that an API key is lost or stolen, it also allows you to revoke access solely for the affected application.

**Use IP allowlisting to restrict where API keys can be used from**

Turnkey supports [IP allowlisting](/security/ip-allowlisting) at both the organization and per-API-key level. For production keys, configure an allowlist that limits requests to known server IPs or CIDR ranges — this ensures that even a leaked key cannot be used from an unauthorized network.

**Use a secret management system to protect your API keys**

Tools like Hashicorp Vault or AWS KMS can help you protect your API key from malicious access.
Expand Down Expand Up @@ -66,8 +66,8 @@ Within this principle of least privilege,

Some actions should be treated more sensitively:

* Adding policies
* Signing transactions
- Adding policies
- Signing transactions

**Use allowlisting if you only send to a set of addresses**

Expand All @@ -79,4 +79,4 @@ If your use case for Turnkey only requires you to send funds to a certain set of
"effect": "EFFECT_ALLOW",
"condition": "eth.tx.to == '<ALLOWED_ADDRESS>'"
}
```
```
1 change: 1 addition & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@
"category/security",
"security/our-approach",
"security/non-custodial-key-mgmt",
"security/ip-allowlisting",
"security/secure-enclaves",
"security/quorum-deployments",
"security/verifiable-data",
Expand Down
34 changes: 17 additions & 17 deletions embedded-wallets/features/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,57 @@ sidebarTitle: "Overview"

<CardGroup>
<Card title="Embedded wallet kit (EWK)" icon="wallet" iconType="duotone" horizontal href="/reference/embedded-wallet-kit">

</Card>

<Card title="Authentication" icon="lock" iconType="duotone" horizontal href="/authentication/overview">

</Card>
<Card title="Delegated access" icon="door-closed" iconType="duotone" horizontal href="/concepts/policies/delegated-access-frontend">

<Card title="Delegated access" icon="door-closed" iconType="duotone" horizontal href="/concepts/policies/delegated-access-frontend">
</Card>
<Card title="Agentic wallets" icon="robot" iconType="duotone" horizontal href="/products/embedded-wallets/features/agentic-wallets">

<Card title="Agentic wallets" icon="robot" iconType="duotone" horizontal href="/products/embedded-wallets/features/agentic-wallets">
</Card>
<Card title="Transaction Management" icon="money-bill-transfer" iconType="duotone" horizontal href="/concepts/transaction-management">

<Card title="Transaction Management" icon="money-bill-transfer" iconType="duotone" horizontal href="/concepts/transaction-management">
</Card>

<Card title="Policy engine" icon="gears" iconType="duotone" horizontal href="/concepts/policies/overview">

</Card>

{" "}

<Card title="Multichain support" icon="diagram-project" iconType="duotone" horizontal href="/products/embedded-wallets/features/multi-chain-support">

</Card>

{" "}

<Card title="Pre-generated wallets" icon="wallet" iconType="duotone" horizontal href="/wallets/pregenerated-wallets">

</Card>

{" "}

<Card title="Sessions" icon="clock" iconType="duotone" horizontal href="/authentication/sessions">

</Card>

<Card title="Account abstraction wallets" icon="users-gear" iconType="duotone" horizontal href="/reference/aa-wallets">

</Card>

<Card title="Import wallets and keys" icon="file-import" iconType="duotone" horizontal href="/wallets/import-wallets">

</Card>

<Card title="Export wallets and keys" icon="file-export" iconType="duotone" horizontal href="/wallets/export-wallets">

</Card>

<Card title="Claim links" icon="link" iconType="duotone" horizontal href="/wallets/claim-links">

</Card>

<Card title="Wagmi" icon="plug" iconType="duotone" horizontal href="/wallets/wagmi">

</Card>

<Card title="Fiat Onramp" icon="money-bill-transfer" iconType="duotone" horizontal href="/wallets/fiat-on-ramp">

</Card>

<Card title="Auth Proxy" icon="server" iconType="duotone" horizontal href="/reference/auth-proxy">

</Card>
</CardGroup>

</CardGroup>
5 changes: 3 additions & 2 deletions getting-started/launch-checklist.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: "Before deploying your Turnkey integration in production, take a lo
- If you are on an Enterprise plan, confirm your production organization ID with your account rep.

<Warning>
Double check our [resource limits](/concepts/resource-limits) and [rate limits](/faq#do-you-have-any-rate-limits-in-place-in-your-public-api) to ensure your implementation will not trigger these limits at production scale.**
Double check our [resource limits](/concepts/resource-limits) and [rate limits](/faq#do-you-have-any-rate-limits-in-place-in-your-public-api) to ensure your implementation will not trigger these limits at production scale.\*\*
</Warning>

## Security
Expand All @@ -19,6 +19,7 @@ Double check our [resource limits](/concepts/resource-limits) and [rate limits](
- Ensure any team members with critical permissions, especially root quorum members, have set up at least two authenticators for their account (e.g., touchID plus a hardware authenticator like a Yubikey).
- Avoid using root user permissions for routine operations and instead use standard users with permissions explicitly granted via policies to limit the surface area of a compromised user.
- Confirm that all API keys are stored securely and not embedded in exposed or vulnerable parts of the codebase. API keys should be stored in a secure, encrypted environment and should never be hard-coded in publicly accessible repositories or client-side code.
- Enable IP allowlisting on your organization and any production API keys to restrict API access to known, authorized networks. For keys used in automated backend workflows, lock them down to specific server IPs or CIDR ranges to prevent misuse even in the event of a key compromise.

## Logging

Expand All @@ -29,4 +30,4 @@ Double check our [resource limits](/concepts/resource-limits) and [rate limits](

- Activity submission is optimistically synchronous. In most cases activities will be completed and returned right away (synchronously), but if there is a lot of activity in a single organization, activities will be processed asynchronously. Make sure you handle PENDING activities by polling a few times until their completion. You can use [createActivityPoller](https://github.com/tkhq/sdk/blob/d9ed2aefc92d298826a40e821f959b019ea1936f/packages/http/src/async.ts#L101) to do this if you're using our Typescript SDK.
- Implement retry strategies for API calls, adjusting for various error types and avoiding over-retrying on critical failures. Incorporate [rate limiting](/faq#do-you-have-any-rate-limits-in-place-in-your-public-api) and exponential backoff in retry mechanisms.
- Set up monitoring to detect and alert on patterns of failures
- Set up monitoring to detect and alert on patterns of failures
64 changes: 26 additions & 38 deletions production-checklist/company-wallet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,42 @@ title: "Company Wallets implementation guide"
description: "Implementing Company Wallets with Turnkey"
---

Turnkey's infrastructure provides a secure, flexible way to manage crypto operations at scale, letting you automate everything from
routine payments and treasury transfers to smart contract deployments and NFT minting.
Turnkey's infrastructure provides a secure, flexible way to manage crypto operations at scale, letting you automate everything from routine payments and treasury transfers to smart contract deployments and NFT minting.

In this guide, we'll walk through the key decisions you'll face integrating Turnkey, and how to design a high-throughput workflow
without compromising on security or user experience.
In this guide, we'll walk through the key decisions you'll face integrating Turnkey, and how to design a high-throughput workflow without compromising on security or user experience.

## Wallet structure: how to organize and scale your wallets

Every transaction starts with a wallet. The way you structure them will shape how scalable and maintainable your automation setup is.

**Option 1:** Single wallet with many accounts (HD path fan-out)
By default, Turnkey wallets use a hierarchical deterministic (HD) structure. That means you can generate unlimited accounts
from a single wallet seed, each with its own address. This is ideal for:
**Option 1:** Single wallet with many accounts (HD path fan-out)\
By default, Turnkey wallets use a hierarchical deterministic (HD) structure. That means you can generate unlimited accounts from a single wallet seed, each with its own address. This is ideal for:

- Managing multiple user deposit addresses
- Creating large numbers of accounts for batching or privacy
- Assigning different onchain roles (e.g. one account for contract deployment, another for transfers)

This approach scales well and stays simple: one wallet, one policy, multiple accounts.

**Option 2:** Multiple wallets in a single org
**Option 2:** Multiple wallets in a single org\
Use this when you need separation by use case. For example:

- One wallet for treasury ops
- One for NFT mints
- One for sequencing contracts

Policies can be set at the wallet level to enforce clear boundaries (e.g. only certain users or services can touch the NFT minting wallet).
Note Turnkey's [resource limits](https://docs.turnkey.com/concepts/resource-limits#resource-limits) and ensure your intended
scaled implementation fits within those limits.
Policies can be set at the wallet level to enforce clear boundaries (e.g. only certain users or services can touch the NFT minting wallet). Note Turnkey's [resource limits](https://docs.turnkey.com/concepts/resource-limits#resource-limits) and ensure your intended scaled implementation fits within those limits.

**Option 3:** Separate sub-orgs per wallet
This option is best when you need strict isolation — e.g. multi-tenant environments, or wallets with different authentication requirements.
Each sub-org has its own root users and policy namespace. Downside: more setup, more moving parts.
**Option 3:** Separate sub-orgs per wallet\
This option is best when you need strict isolation — e.g. multi-tenant environments, or wallets with different authentication requirements. Each sub-org has its own root users and policy namespace. Downside: more setup, more moving parts.

Most teams use a combination: they generate many accounts under a few wallets and reserve sub-orgs for user-facing or high-risk cases.

## Trigger model: what kicks off transactions

Transaction automation can be reactive, proactive, or user-driven. The right model depends on your use case.

**Event-driven (most common):**
**Event-driven (most common):**\
A transaction is triggered by an external event — a webhook, an internal job, or an offchain signal. Examples:

- Market resolution triggers a payout
Expand All @@ -53,21 +47,21 @@ A transaction is triggered by an external event — a webhook, an internal job,

Use a background worker or event system to translate that trigger into a signing request.

**Scheduled:**
**Scheduled:**\
Useful for treasury management, yield compounding, or periodic distribution flows. Run a job hourly/daily and trigger signing from there.

**Manual with automation fallback:**
Sometimes a human should have the final say, but you want the transaction to be ready to go. You can submit a tx to Turnkey
that requires approval, then notify a signer via Slack, email, or dashboard.
**Manual with automation fallback:**\
Sometimes a human should have the final say, but you want the transaction to be ready to go. You can submit a tx to Turnkey that requires approval, then notify a signer via Slack, email, or dashboard.

Tip: Think in terms of "intent capture" (when does your system decide something needs to happen) vs. "signing execution"
(when and how does it actually get signed).
Tip: Think in terms of "intent capture" (when does your system decide something needs to happen) vs. "signing execution" (when and how does it actually get signed).

## Policy model: what rules do you want enforced?

Policies are your automation safety net. Every action goes through the policy engine before it's allowed, and is explicitly denied by default.

You'll want to decide:
For an additional layer of network-level protection, consider enabling [IP allowlisting](/security/ip-allowlisting) to restrict which source IPs can make API requests in the first place — a useful complement to policy rules for backend automation keys.

You'll want to decide:\
**How many approvers?**

- Use single-party approvals for low-risk flows (e.g. daily payouts)
Expand Down Expand Up @@ -98,17 +92,16 @@ Most automation systems have 3-5 core policies and evolve them as their product

All interfaces (CLI, SDK, API) go through the same policy and enclave flow. The only difference is where your logic lives.

**CLI:**
**CLI:**\
Best for prototyping or scripting internal workflows (e.g. rotate a key, create a wallet). You can also use it in CI pipelines.

**SDK:**
Ideal for integrating into apps or backend services. Available in multiple programming languages. Handles signing, retries,
and activity submission.
**SDK:**\
Ideal for integrating into apps or backend services. Available in multiple programming languages. Handles signing, retries, and activity submission.

**Direct API:**
**Direct API:**\
Use this if you want full control or are building from a non-standard language. Slightly more effort to get right, but fully supported.

**Dashboard:**
**Dashboard:**\
Not for automation — but useful for manual approval flows, audit trails, and monitoring.

**Common pattern:**
Expand All @@ -120,22 +113,17 @@ Not for automation — but useful for manual approval flows, audit trails, and m

Graveyard - add back when IndexedDb launches

By default, session keys are stored in IndexedDB when running in the browser. These keys are non-extractable and can't be accessed by your app,
by Turnkey, or by anything else running on the page. On mobile, session keys will typically be stored in the device's secure storage layer
(e.g. Keychain or Keystore) depending on the SDK and environment.
By default, session keys are stored in IndexedDB when running in the browser. These keys are non-extractable and can't be accessed by your app, by Turnkey, or by anything else running on the page. On mobile, session keys will typically be stored in the device's secure storage layer (e.g. Keychain or Keystore) depending on the SDK and environment.

The biggest decision is how long sessions should last. Longer-lived sessions reduce friction, enabling users to stay signed in across reloads,
tabs, or app restarts. For most embedded wallet use cases, long-lived sessions in IndexedDB strike a good balance between usability and safety.
The biggest decision is how long sessions should last. Longer-lived sessions reduce friction, enabling users to stay signed in across reloads, tabs, or app restarts. For most embedded wallet use cases, long-lived sessions in IndexedDB strike a good balance between usability and safety.

Scoping
Scoping\
You'll also want to decide whether your sessions should be scoped.

Scoped sessions allow you to define exactly what a given session key is allowed to do — and enforce it via Turnkey's policy engine. For example,
you can issue sessions that:
Scoped sessions allow you to define exactly what a given session key is allowed to do — and enforce it via Turnkey's policy engine. For example, you can issue sessions that:

- are read-only
- can only sign transactions below a certain value
- can only interact with specific contracts or functions (e.g. a swap function on Uniswap)

This gives you a flexible way to enforce step-up authentication flows (e.g. OTP for read-only, passkey + OTP for full signing),
build approval-based transaction flows, or safely grant session access in more complex environments.
This gives you a flexible way to enforce step-up authentication flows (e.g. OTP for read-only, passkey \+ OTP for full signing), build approval-based transaction flows, or safely grant session access in more complex environments.
Loading