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

# How-to: Generate and register your entity secret

> Generate an entity secret and register it with Circle.

An [entity secret](/wallets/dev-controlled/entity-secret-management) is a
cryptographic key. Circle uses it to authorize signing on your
developer-controlled wallets. You must generate and register an entity secret
before creating any developer-controlled wallets.

## Prerequisites

Before you begin, ensure you've:

* Created an API key in the [Circle Console](https://console.circle.com/).
* Installed [Node.js 22+](https://nodejs.org/) or
  [Python 3.11+](https://www.python.org/).
* Installed the developer-controlled wallets SDK:

<CodeGroup>
  ```shell Node.js theme={null}
  npm install @circle-fin/developer-controlled-wallets
  ```

  ```shell Python theme={null}
  pip install circle-developer-controlled-wallets python-dotenv
  ```
</CodeGroup>

<Note>
  If you are not using the Circle SDK, you can generate and register your entity
  secret [manually](https://github.com/circlefin/w3s-entity-secret-sample-code)
  using standard libraries or command-line tools.
</Note>

## Generate and register an entity secret

Create your script file with `touch register-entity-secret.ts` (Node.js) or
`touch register_entity_secret.py` (Python), then add the following script,
which:

* Generates a 32-byte entity secret
* Registers it with Circle
* Saves the recovery file to `./recovery/` with a unique filename
* Adds `CIRCLE_ENTITY_SECRET` to your `.env` file for local development (use a
  secrets manager in production)

It expects `CIRCLE_API_KEY` in your environment.

<CodeGroup>
  ```typescript Node.js theme={null}
  import { randomBytes } from "node:crypto";
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
  import { registerEntitySecretCiphertext } from "@circle-fin/developer-controlled-wallets";

  const apiKey: string | undefined = process.env.CIRCLE_API_KEY;
  if (!apiKey) {
    throw new Error("CIRCLE_API_KEY is required. Set it in .env first.");
  }

  // Refuse to overwrite an existing entity secret in .env.
  const existingEnv: string = existsSync(".env")
    ? readFileSync(".env", "utf8")
    : "";
  if (/^CIRCLE_ENTITY_SECRET=/m.test(existingEnv)) {
    throw new Error(
      "CIRCLE_ENTITY_SECRET already exists in .env. Refusing to overwrite it.",
    );
  }

  // Generate a 32-byte entity secret. The SDK's generateEntitySecret() helper
  // prints to stdout but doesn't return the value, so use crypto directly.
  const entitySecret: string = randomBytes(32).toString("hex");
  const recoveryFilePath: string = "./recovery";

  mkdirSync(recoveryFilePath, { recursive: true });

  await registerEntitySecretCiphertext({
    apiKey,
    entitySecret,
    recoveryFileDownloadPath: recoveryFilePath,
  });

  // For production, prefer a secrets manager over .env.
  appendFileSync(".env", `\nCIRCLE_ENTITY_SECRET=${entitySecret}\n`);

  console.log("Entity secret registered.");
  console.log(`Recovery file saved to a new file in: ${recoveryFilePath}`);
  console.log("CIRCLE_ENTITY_SECRET added to .env");
  ```

  ```python Python theme={null}
  import os
  import re

  from dotenv import load_dotenv
  from circle.web3 import utils

  load_dotenv()

  api_key = os.environ.get("CIRCLE_API_KEY")
  if not api_key:
      raise RuntimeError("CIRCLE_API_KEY is required. Set it in .env first.")

  existing_env = ""
  if os.path.exists(".env"):
      with open(".env", "r") as f:
          existing_env = f.read()

  if re.search(r"^CIRCLE_ENTITY_SECRET=", existing_env, re.MULTILINE):
      raise RuntimeError(
          "CIRCLE_ENTITY_SECRET already exists in .env. Refusing to overwrite it."
      )

  entity_secret = os.urandom(32).hex()
  recovery_file_path = "./recovery"

  os.makedirs(recovery_file_path, exist_ok=True)

  utils.register_entity_secret_ciphertext(
      api_key=api_key,
      entity_secret=entity_secret,
      recoveryFileDownloadPath=recovery_file_path,
  )

  with open(".env", "a") as f:
      f.write(f"\nCIRCLE_ENTITY_SECRET={entity_secret}\n")

  print("Entity secret registered.")
  print(f"Recovery file saved to a new file in: {recovery_file_path}")
  print("CIRCLE_ENTITY_SECRET added to .env")
  ```
</CodeGroup>

<Warning>
  **Secure your entity secret and recovery file.**

  Store your entity secret in a secrets manager or encrypted password manager.
  Save the recovery file to a separate, secure location. It is the only way to
  reset your entity secret if it is lost. Circle does not store your entity secret
  and cannot recover it for you. For more on storage and rotation best practices,
  see
  [How the entity secret works](/wallets/dev-controlled/entity-secret-management).
</Warning>

### Run the script

From the same directory, run:

<CodeGroup>
  ```shell Node.js theme={null}
  npx tsx --env-file=.env register-entity-secret.ts
  ```

  ```shell Python theme={null}
  python register_entity_secret.py
  ```
</CodeGroup>

You should see:

```text theme={null}
Entity secret registered.
Recovery file saved to a new file in: ./recovery
CIRCLE_ENTITY_SECRET added to .env
```

<Note>
  If you see `Cannot find module '@circle-fin/developer-controlled-wallets'`,
  run the script from the same directory where you ran `npm install` (or `pip
      install`). The SDK lives in that project's `node_modules` or `virtualenv` and
  isn't visible from other folders.
</Note>
