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

# Authentication

> Understand Mesa private keys, access tokens, and how commits are attributed.

Mesa has two credentials for programmatic access:

1. **Private keys**: long-lived signing credentials meant for use in trusted environments (ex. your application server).
2. **Access tokens** (JWTs): short-lived tokens meant for use in ephemeral, less-trusted environments (ex. an agent sandbox).

If an SDK client still uses an API key, follow [Migrate from API keys](/content/getting-started/migrate-from-api-keys) before upgrading it.

Private keys can mint access tokens, but access tokens cannot be used to mint more credentials.

Keep private keys in trusted infrastructure. Use access tokens anywhere you would be uncomfortable leaving a durable secret behind: agent sandboxes, disposable VMs, container sessions, or per-user agent jobs.

A private key is never sent to Mesa. The SDK signs access tokens with it locally, and Mesa stores only the matching public key, so minting a token requires no network round-trip.

## Basic Usage

Create a key in the **Keys** section of your organization's settings in the [dashboard](https://app.mesa.dev). The private key is shown once, so save it to your secrets manager as `MESA_PRIVATE_KEY` before leaving the page.

Construct SDK clients with the private key in your trusted backend:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Mesa } from "@mesadev/sdk";

  const mesa = new Mesa({ privateKey: process.env.MESA_PRIVATE_KEY });
  ```

  ```python Python theme={null}
  import os
  from mesa_sdk import Mesa

  mesa = Mesa(private_key=os.environ["MESA_PRIVATE_KEY"])
  ```
</CodeGroup>

## Authors

Every commit in Mesa records who made it. Since agents and humans often work on the same repository, a commit can have several authors: for example the user a session belongs to plus the agent doing the edits.

Each operation that creates commits takes an ordered `authors` list. Private-key layout definitions take one too (`mesa.fs({ layout, authors })`), because writes through the mount become commits.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { repo } from "@mesadev/sdk";

  // The user the work belongs to first, then the agent that did it.
  const authors = [
    { name: "Jane Doe", email: "jane@acme.dev" },
    { name: "Acme Agent" }, // email is optional
  ];

  // Writes through an app mount become commits, so the layout definition takes authors.
  const fs = await mesa.fs({
    layout: {
      "/workspace": repo("agent-workspace", { mode: "rw", at: { bookmark: "main" } }),
    },
    authors,
  }).mount();

  // Commit operations take the same list.
  await mesa.bookmarks.merge({
    repo: "agent-workspace",
    target: "main",
    source: "agent-draft",
    authors,
  });
  ```

  ```python Python theme={null}
  from mesa_sdk import repo

  # The user the work belongs to first, then the agent that did it.
  authors = [
      {"name": "Jane Doe", "email": "jane@acme.dev"},
      {"name": "Acme Agent"},  # email is optional
  ]

  # Writes through an app mount become commits, so the layout definition takes authors.
  async with mesa.fs(
      layout={"/workspace": repo("agent-workspace", mode="rw", at={"bookmark": "main"})},
      authors=authors,
  ).mount() as fs:
      ...

  # Commit operations take the same list.
  await mesa.bookmarks.merge(
      repo="agent-workspace",
      target="main",
      source="agent-draft",
      authors=authors,
  )
  ```
</CodeGroup>

Mesa preserves the order of the `authors` list. The first entry is the primary author; the rest are co-authors. In the example above, Jane owns the commits and the agent is credited alongside her.

## Minting Access Tokens

Use `mesa.tokens.create(...)` when you need to hand a credential to another environment, such as a sandbox where the Mesa CLI will run. The token carries its own authors, so anything the sandbox writes is attributed the same way.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { token } = await mesa.tokens.create({
    authors: [{ name: "Mesa Bot", email: "mesa-bot@example.com" }],
    scopes: ["read", "write"],
    repos: ["acme/agent-workspace"],
    ttl_seconds: 60 * 60, // 1 hour; max 4 hours
  });

  await createSandbox({
    env: { MESA_ACCESS_TOKEN: token },
  });
  ```

  ```python Python theme={null}
  minted = await mesa.tokens.create(
      authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
      scopes=["read", "write"],
      repos=["acme/agent-workspace"],
      ttl_seconds=60 * 60,  # 1 hour; max 4 hours
  )

  create_sandbox(
      env={"MESA_ACCESS_TOKEN": minted.token},
  )
  ```
</CodeGroup>

See [Daytona](/content/integrations/sandboxes/daytona) for a full end-to-end example of this flow with a real sandbox provider.

Pass `repos` to restrict a token to specific repositories and `scopes` to cap what it can do.

Tokens default to a 15 minute TTL, have a maximum TTL of 4 hours, and are not refreshed automatically. A mount uses one token for its whole lifetime, so choose a TTL that covers the mount's work.

Inside the receiving environment, the Mesa CLI reads the token from `MESA_ACCESS_TOKEN`. SDK clients accept one through `auth`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const mesa = new Mesa({ auth: { accessToken } });
  ```

  ```python Python theme={null}
  mesa = Mesa(auth={"access_token": access_token})
  ```
</CodeGroup>

A client built from an access token can only forward that token. It cannot mint new ones.

## API Keys

API keys are deprecated in favor of private keys, and new integrations should use private keys. Existing API keys remain supported by the CLI, direct REST integrations, and MesaFS. The TypeScript and Python SDKs no longer accept API keys as client credentials or read `MESA_API_KEY`, so migrate those clients before upgrading them. API keys are long-lived bearer credentials, so keep them in trusted processes just like private keys.

See [Migrate from API keys](/content/getting-started/migrate-from-api-keys) for SDK migration steps and the [Authentication reference](/content/reference/authentication) for exact credential behavior and limits.
