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

# Authentication

> How to authenticate requests to the Legend API

# Authentication

The Legend API uses **bearer token authentication**. Every request must include a query key or JWT in the `Authorization` header.

## Three auth methods

| Method          | Best for                                | Duration      |
| --------------- | --------------------------------------- | ------------- |
| **Query Key**   | Programmatic access, CI/CD, SDKs        | Until revoked |
| **OAuth JWT**   | CLI, MCP agents, browser-based flows    | 30 days       |
| **OAuth (MCP)** | Claude Code, Cursor (remote MCP server) | 30 days       |

## Query keys

Get a query key from [dashboard.legend.xyz](https://dashboard.legend.xyz) under **Settings > API Keys**:

```
qk_abc123_8f2e9a7b4c1d6e3f5a0b
```

Treat it like a password — store it in environment variables or a secrets manager, never in source code.

## OAuth login (CLI)

The `legend-cli` can authenticate via Google SSO:

```bash theme={null}
legend-cli login
```

This opens your browser, completes the OAuth flow, and saves a JWT (valid for 30 days) to your profile. All subsequent CLI and local MCP commands use this token automatically.

## Making requests

Include your query key or JWT as a bearer token:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://prime-api.legend.xyz/accounts \
    -H "Authorization: Bearer $LEGEND_QUERY_KEY"
  ```

  ```typescript TypeScript theme={null}
  import { LegendPrime } from "legend-prime";

  const client = new LegendPrime({
    queryKey: process.env.LEGEND_QUERY_KEY,
  });
  ```

  ```python Python theme={null}
  from legend_prime import LegendPrime

  client = LegendPrime(
      query_key=os.environ["LEGEND_QUERY_KEY"],
  )
  ```

  ```rust Rust theme={null}
  use legend_client::{LegendPrime, Config};

  let client = LegendPrime::new(Config {
      query_key: std::env::var("LEGEND_QUERY_KEY").unwrap(),
      base_url: None,
  });
  ```
</CodeGroup>

## Two layers of auth

The Legend API separates **API access** from **fund authorization**:

| Layer          | What it does                                                          | Who has it           |
| -------------- | --------------------------------------------------------------------- | -------------------- |
| **Query key**  | Authenticates API requests — read data, create accounts, create plans | Your server          |
| **Signer key** | Authorizes on-chain transactions — earn, withdraw, transfer           | You or your end-user |

Your query key lets you do everything *except* move funds. To execute a plan, the sub-account's signer must produce an EIP-712 signature. The signer key — whether an EOA private key or a Turnkey-managed P256 key — is controlled by you or your end-user at your discretion. Legend never holds it.

See [Signer types](/introduction#signer-types) for more on EOA vs Turnkey P256.

## Key rotation

You can have multiple active query keys for the same Prime Account. To rotate:

1. Create a new query key
2. Update your application to use the new key
3. Revoke the old key

Both keys work simultaneously until you revoke the old one — no downtime.

## Security best practices

* Store query keys in environment variables or a secrets manager
* Use separate keys for production and development
* Rotate keys periodically and immediately if compromised
* Query keys grant access to all sub-accounts under your Prime Account — scope access at the application level if needed
