> ## Documentation Index
> Fetch the complete documentation index at: https://docs.turnkey.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Turnkey is wallet infrastructure: create and manage crypto wallets, sign transactions, and enforce policy-based access controls. Best-fit uses: embedded consumer wallets (email/passkey/social auth, no seed phrases), automated onchain operations with server-side wallets, AI agent wallets with policy-scoped signing, enterprise key management, and verifiable off-chain workloads on Turnkey Verifiable Cloud (TVC).
> Every API call is a JSON POST to https://api.turnkey.com signed with a P-256 API key; create an organization and key self-serve at https://app.turnkey.com.
> Key Turnkey developer resources: API reference (https://docs.turnkey.com/api-reference/overview/intro.md), OpenAPI spec (https://docs.turnkey.com/public_api.swagger.json), authentication (https://docs.turnkey.com/features/authentication/overview.md), webhooks (https://docs.turnkey.com/features/webhooks/overview.md), MCP server for docs search (https://docs.turnkey.com/mcp), skill for building with Turnkey (https://docs.turnkey.com/skill.md), agent skills for operating an organization (https://docs.turnkey.com/get-started/ai-skills.md), CLI (https://docs.turnkey.com/sdks/cli.md), SDK reference (https://docs.turnkey.com/sdks/introduction.md), full docs content (https://docs.turnkey.com/llms-full.txt).

# JWT Auth for TVC Apps

> Let Turnkey policy decide who can call your Turnkey Verifiable Cloud app, including non-custodial apps that act on customers' keys.

> [!WARNING]
>
> Mint JWT is in beta and is enabled per organization.
> [Contact sales](https://www.turnkey.com/contact-us) to turn it on.

## Who can call your app?

A [TVC](https://docs.turnkey.com/features/verifiable-cloud/overview.md) app can hold keys that move money, such as [exchange API keys](https://docs.turnkey.com/solutions/verifiable-cloud/enclave-only-secrets.md). Protecting the key is half the job. The other half is deciding who may ask the app to use it.

If the app trusts an API key held by your backend, anyone who compromises the backend can call it. With [Mint JWT](https://docs.turnkey.com/features/mint-jwt.md), the app instead accepts only requests that carry a Turnkey-signed JWT. Turnkey's policy engine decides who gets one, and each token authorizes one exact request.

```mermaid theme={"system"}
flowchart LR
    U["Caller"] -- "1. mint JWT for this request" --> T["Turnkey<br/>policy and approvals"]
    T -- "2. JWT" --> U
    U -- "3. request + JWT" --> A["TVC app<br/>verifies, then acts"]
    A -- "4. signed request" --> V["Exchange"]
```

> [!NOTE]
>
> The examples on this page use exchange API keys. The same pattern works for any TVC app that needs to authenticate its callers.

## Who approves

| | Trading firm | Consumer trading platform |
| :- | :- | :- |
| Who holds the venue key | The firm's own organization | Each customer's [sub-organization](https://docs.turnkey.com/features/sub-organizations.md) |
| Who mints | A service user | Your strategy user for orders, if the customer allows it. The customer for withdrawals |
| Who sets the rules | Your administrator quorum | The customer, in their own sub-organization |
| What the platform can't do | Withdraw without the administrators | Act outside the policies the customer sets |

### Trading firm: administrator quorum

Your trading system mints tokens as a service user. Orders need only the service user. Withdrawals also need two administrators:

```json theme={"system"}
{
  "policyName": "Withdrawal tokens need two administrators",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(u, u.id == '<TRADING_SERVICE_USER_ID>') &&
    approvers.filter(u, u.tags.contains('<ADMIN_TAG_ID>')).count() >= 2",
  "condition": "activity.type == 'ACTIVITY_TYPE_MINT_JWT' &&
    jwt.profile.httpz.audience == 'https://app.example.com' &&
    jwt.profile.httpz.method == 'POST' &&
    jwt.profile.httpz.path == '/withdrawals'"
}
```

The `jwt.profile.httpz` policy fields are coming soon. See [Mint JWT](https://docs.turnkey.com/features/mint-jwt.md#who-can-mint) for the order policy.

### Consumer trading platform: the customer approves

Your platform runs trading strategies for customers on their own exchange accounts. Auth to your app is non-custodial: each customer owns the policies that decide who can mint tokens for their account, and your platform can't change them.

1. Each customer gets a sub-organization and is its root user. They import their exchange API key there, so it never passes through your systems.

2. Your TVC app has a [delegated access](https://docs.turnkey.com/features/policies/delegated-access/overview.md) user in the sub-organization. Policy lets only that user export the key, encrypted to the app's enclave.

3. The customer writes a policy that lets your strategy user mint order tokens for their account:

   ```json theme={"system"}
   {
     "policyName": "My strategy can place orders for me",
     "effect": "EFFECT_ALLOW",
     "consensus": "approvers.any(u, u.id == '<STRATEGY_USER_ID>')",
     "condition": "activity.type == 'ACTIVITY_TYPE_MINT_JWT' &&
       jwt.profile.httpz.audience == 'https://app.example.com' &&
       jwt.profile.httpz.method == 'POST' &&
       jwt.profile.httpz.path == '/orders'"
   }
   ```

4. No policy allows withdrawal tokens, so only the customer can mint one, with their passkey.

5. The app checks that the token's `org` is the customer's sub-organization, and that `sub` may call that route: the strategy user for orders, the customer for withdrawals.

The customer can delete the policy at any time to stop automated trading. Give your delegated users no permission to create or edit policies, so your platform can only act within the rules each customer sets. Customers can also [verify the app's code](https://docs.turnkey.com/features/verifiable-cloud/proofs-and-verification.md) before they import their key.

## What the app checks

For every request, the app [verifies the token](https://docs.turnkey.com/features/mint-jwt.md#verify-a-token):

* The signature, against Turnkey's published keys for the issuer.
* The audience is the app's own origin, and the token hasn't expired.
* The token's method, path, query, and body digest match this request.
* The subject and organization may make this request.

In Rust, [`turnkey_jwt_profiles`](https://docs.rs/turnkey_jwt_profiles) does these checks for you.

## Getting set up

**1. Deploy the app**

Deploy your app on TVC and give it the venue keys it needs. See [Enclave only secrets](https://docs.turnkey.com/solutions/verifiable-cloud/enclave-only-secrets.md).

**2. Require a JWT on every route**

Reject any request without a valid Turnkey JWT for that exact request.

**3. Write the minting policies**

Decide who mints each kind of request and who approves. Keep the quorum at 1 while you build, and raise it before production.

**4. Mint from your clients**

Call `mintJwt` from your trading system or your customer's app, then send the request with the token.

## Get started

[Contact us](https://www.turnkey.com/contact-us) to enable Mint JWT and design your app's authorization with our team.

Mint JWT

Request-bound JWTs signed after policy approval.

[Open](https://docs.turnkey.com/features/mint-jwt.md)

![](https://docs.turnkey.com/images/solutions/light/tvc.svg)

Enclave only secrets

Use your most critical keys only inside an attested app.

[Open](https://docs.turnkey.com/solutions/verifiable-cloud/enclave-only-secrets.md)

Sub-organizations

Give each customer their own organization and keys.

[Open](https://docs.turnkey.com/features/sub-organizations.md)

Turnkey Verifiable Cloud

Deploy apps with verifiable code and secure keys.

[Open](https://docs.turnkey.com/features/verifiable-cloud/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.