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

# Access Scopes

> The two scope sets that bound what a session key may do.

Every [session key](/authentication/session-keys) carries **two independent scope sets**, enforced by two different layers:

* **Protocol scopes** — on-chain authority. Signed into each action and re-validated by the protocol state machine. These decide what state-changing actions the key can authorize.
* **Off-chain scopes** — server-side capabilities. Never signed, never seen by the protocol; enforced only by the server before a request is processed.

<Note>All of the steps in this guide can be done through the UX or SDKs.</Note>

## Protocol scopes

Protocol scopes form a **tree**. A grant for a branch covers everything under it, so `trade:all` covers `trade:orderbook:all` and `trade:rfq:option` alike, and `all` at any level covers its children. A request is checked by asking whether one of the key's grants *allows* the specific scope the action requires.

<Frame>
  <img className="block dark:hidden bg-white" src="https://mintcdn.com/derive-a0490cef/BhszcT-bQHpTuFnc/authentication/protocol-scopes-light.png?fit=max&auto=format&n=BhszcT-bQHpTuFnc&q=85&s=96dc88b66009b358895daa16bfc5c1eb" alt="Diagram of the Derive protocol scope tree. The root grant `admin` sits above the branches trade, transfer, withdraw, liquidate, create_session_key, and vault; a grant on any node implicitly covers all of its descendants (for example `trade:all` covers `trade:orderbook:all` and `trade:rfq:option`, and `all` at any level covers its children). The trade branch nests by venue (orderbook, rfq) and then instrument (perp, option, spot), and each node is labeled with the exact wire string a key is granted (e.g. `trade:orderbook:all`, `transfer:existing_subaccount`). A session key with no protocol scopes is read-only. A request is authorized by checking whether one of the key's grants allows the specific scope the action requires." width="1712" height="1534" data-path="authentication/protocol-scopes-light.png" />

  <img className="hidden dark:block bg-black" src="https://mintcdn.com/derive-a0490cef/BhszcT-bQHpTuFnc/authentication/protocol-scopes.png?fit=max&auto=format&n=BhszcT-bQHpTuFnc&q=85&s=b972b12f5a638c813d8357f83d3315a0" alt="Diagram of the Derive protocol scope tree. The root grant `admin` sits above the branches trade, transfer, withdraw, liquidate, create_session_key, and vault; a grant on any node implicitly covers all of its descendants (for example `trade:all` covers `trade:orderbook:all` and `trade:rfq:option`, and `all` at any level covers its children). The trade branch nests by venue (orderbook, rfq) and then instrument (perp, option, spot), and each node is labeled with the exact wire string a key is granted (e.g. `trade:orderbook:all`, `transfer:existing_subaccount`). A session key with no protocol scopes is read-only. A request is authorized by checking whether one of the key's grants allows the specific scope the action requires." width="1712" height="1534" data-path="authentication/protocol-scopes.png" />
</Frame>

## Off-chain scopes

Off-chain scopes are exact-match only — no tree, no hierarchy.

| Wire string          | Grants                                                                                                                                                                                                                               |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `account_info`       | Read-tier account capability. This is the scope synthesized for JWT (wallet-token) sessions — the capability a logged-in browser session holds. Gates `private/change_subaccount_label` and a label-only `private/edit_session_key`. |
| `delete_session_key` | Intended to guard session-key deletion, which the protocol itself does not restrict.                                                                                                                                                 |

## Defaults and how scopes are set

There is no implicit default: a newly created key holds **exactly** the scopes its create request carried. Omit `protocol_scopes` and the key has no protocol authority; omit `offchain_scopes` and it has no off-chain capability.

Two scope sets are also synthesized at auth time (not stored):

* **Direct wallet auth** → protocol `admin`, no off-chain scopes (admin bypasses off-chain gates).
* **JWT / wallet-token auth** → off-chain `account_info`, no protocol scopes (read-only; cannot authorize actions).

<Steps>
  <Step title="Create — set both scope sets">
    Call `private/create_session_key`. The caller must hold the `create_session_key` protocol scope. `protocol_scopes`
    are ABI-encoded into the signed action and re-validated in-protocol; `offchain_scopes` are validated but stay
    server-side. Child scopes must be a subset of the signing parent (delegated attenuation).
  </Step>

  <Step title="Edit — off-chain fields only">
    Call `private/edit_session_key` to change `label`, `ip_whitelist`, or `offchain_scopes`. **Protocol scopes are not
    editable here** — to add or remove protocol authority, create a new key.
  </Step>
</Steps>

<CodeGroup>
  ```typescript TypeScript (SDK) theme={null}
  import { Wallet } from 'ethers';
  import {
    DeriveClient,
    OffchainScope,
    ProtocolScopeCode,
  } from '@derivexyz/derive-ts';

  const client = new DeriveClient({
    network: 'testnet',
    wallet: process.env.PRIVATE_KEY!,
  });

  // create_session_key is an action-signed private call: open and authenticate first.
  await client.connect();
  await client.login();

  // Generate the key locally — only its address is registered.
  const sessionKey = Wallet.createRandom();

  const created = await client.sessionKeys.create({
    publicSessionKey: sessionKey,
    expirySec: Math.floor(Date.now() / 1000) + 30 * 24 * 3600, // the KEY's lifetime: 30 days
    protocolScopes: [
      ProtocolScopeCode.TradeOrderbookAll,
      ProtocolScopeCode.TradeRfqOption,
    ],
    offchainScopes: [OffchainScope.AccountInfo],
    label: 'trading-bot',
  });

  // The ack echoes exactly what the key holds — there is no implicit default:
  console.log(created.protocol_scopes); // ['trade:orderbook:all', 'trade:rfq:option']
  console.log(created.offchain_scopes); // ['account_info']
  ```

  ```python Python (SDK) theme={null}
  # Coming soon.
  ```

  ```rust Rust (SDK) theme={null}
  // Coming soon.
  ```

  ```bash cURL theme={null}
  # Body nonce/signature: EIP-712 action signing under the create-session-key
  # module (see /action-signing). X-Derive* headers: session auth (see /json-rpc).
  curl -X POST https://api.derive.xyz/v3/private/create_session_key \
    -H "Content-Type: application/json" \
    -H "X-DeriveWallet: $WALLET_ADDRESS" \
    -H "X-DeriveTimestamp: $TS" \
    -H "X-DeriveSignature: $SIG" \
    -d '{
      "wallet": "0xYourWallet",
      "public_session_key": "0xSessionKeyAddress",
      "expiry_sec": 1733592000,
      "subaccount_ids": null,
      "nonce": "1730999700000123000",
      "signature_expiry_sec": 1731000600,
      "signer": "0xYourWallet",
      "signature": "0x…",
      "protocol_scopes": ["trade:orderbook:all", "trade:rfq:option"],
      "offchain_scopes": ["account_info"],
      "label": "trading-bot"
    }'
  ```
</CodeGroup>

<Note>
  See [Session keys](/authentication/session-keys) for the full create / edit / list lifecycle and
  [Authentication](/authentication/session-login) for how a session resolves to protocol and off-chain scopes. Amounts
  and constants referenced by signed actions live on [Action signing](/authentication/action-signing).
</Note>


## Related topics

- [New features](/migrating/new-features.md)
- [Market Maker Protection](/trading/market-maker-protection.md)
- [Session Keys](/authentication/session-keys.md)
