Skip to main content
Mesa uses API keys for authentication. Each key is scoped to an organization and can be granted specific permissions to control access to repositories and operations.

API Keys

API keys provide programmatic access to the Depot API and Git operations. Keys are prefixed with mesa_ and should be kept secure.

Creating API Keys

You can create API keys through the SDK or API. This is useful if you want to generate scoped keys to put in a sandbox or within CI:
import { Mesa } from "@mesadev/sdk";

const mesa = new Mesa({ apiKey: process.env.MESA_API_KEY });

const key = await mesa.admin.createApiKey({
  org: "my-org",
  body: {
    name: "CI/CD Pipeline",
    scopes: ["git:read", "git:write", "repo:read"],
  },
});

// Store this securely - the full key is only shown once!
console.log(key.key); // mesa_abc123...
API keys are only displayed once when created. Store them securely in your secrets manager or environment variables.

Using API Keys

SDK Authentication

import { Mesa } from "@mesadev/sdk";

const mesa = new Mesa({
  apiKey: "<API_KEY>",
});
Or using environment variables:
export MESA_API_KEY=<API_KEY>
const mesa = new Mesa({
  apiKey: process.env.MESA_API_KEY,
});

HTTP API Authentication

Include the API key in the Authorization header:
curl -H "Authorization: Bearer <API_KEY>" \
  https://api.mesa.dev/my-org/repos

Git Authentication

Use the API key as the password when cloning or pushing:
# Clone with API key
git clone https://t:<API_KEY>@api.mesa.dev/my-org/my-repo.git

Managing API Keys

Listing Keys

const { apiKeys } = await mesa.admin.listApiKeys({ org: "my-org" });

for (const key of apiKeys) {
  console.log(`${key.name}: ${key.id} (${key.scopes.join(", ")})`);
}
The full API key value is never returned when listing keys - only the key ID, name, and metadata.

Revoking Keys

await mesa.admin.revokeApiKey({
  org: "my-org",
  id: "key_abc123",
});
Revoked keys are immediately invalidated and cannot be used for authentication.

Permission Scopes

API keys are granted specific scopes that control what operations they can perform. Use the principle of least privilege - only grant the scopes necessary for each use case.

Available Scopes

ScopeDescription
git:readClone and fetch repositories
git:writePush commits to repositories (includes git:read)
repo:readRead repository metadata, branches, commits, and content
repo:createCreate new repositories and update existing ones
repo:deleteDelete repositories
webhook:readList repository webhooks
webhook:writeCreate and delete repository webhooks
adminFull access to all operations including API key management

Scope Hierarchy

Some scopes implicitly include others:
  • git:write includes git:read - A key with write access can also read
  • admin includes all scopes - Full access to everything

Scope Requirements by Operation

Repository Operations

OperationRequired Scope
List repositoriesrepo:read
Get repositoryrepo:read
Create repositoryrepo:create
Update repositoryrepo:create
Delete repositoryrepo:delete

Content & History

OperationRequired Scope
Get file contentrepo:read
List branchesrepo:read
List commitsrepo:read
Get commitrepo:read
Get diffrepo:read

Git Operations

OperationRequired Scope
Clone (git fetch)git:read
Push (git push)git:write
Create commit (API)git:write
Create branchgit:write
Delete branchgit:write

Webhooks

OperationRequired Scope
List webhookswebhook:read
Create webhookwebhook:write
Delete webhookwebhook:write

Administration

OperationRequired Scope
Create API keyadmin
List API keysadmin
Revoke API keyadmin

Default Scopes

When creating an API key without specifying scopes, the following defaults are applied:
["git:read", "git:write", "repo:read", "repo:create"]
This provides common access for development workflows without repository deletion or admin capabilities.

Best Practices

Use Scoped Keys

Create separate API keys for different purposes with minimal required scopes:
// CI/CD key - only needs to read and write code
await mesa.admin.createApiKey({
  org: "my-org",
  body: {
    name: "GitHub Actions",
    scopes: ["git:read", "git:write", "repo:read"],
  },
});

// Read-only key for analytics
await mesa.admin.createApiKey({
  org: "my-org",
  body: {
    name: "Analytics Service",
    scopes: ["repo:read"],
  },
});

// Deployment key - can create repos but not delete
await mesa.admin.createApiKey({
  org: "my-org",
  body: {
    name: "Deployment Service",
    scopes: ["git:read", "git:write", "repo:read", "repo:create"],
  },
});

Error Handling

Authentication Errors

try {
  await mesa.repos.list({ org: "my-org" });
} catch (error) {
  if (error.code === "UNAUTHORIZED") {
    // Invalid or missing API key
    console.error("Check your API key");
  }
}

Permission Errors

try {
  await mesa.repos.delete({ org: "my-org", repo: "important-repo" });
} catch (error) {
  if (error.code === "FORBIDDEN") {
    // API key lacks required scope
    console.error("API key needs repo:delete scope");
  }
}

Organization Access

API keys are scoped to a single organization. Attempting to access a different organization returns a forbidden error:
// Key belongs to "org-a"
const mesa = new Mesa({ apiKey: orgAKey });

// This will fail - wrong organization
await mesa.repos.list({ org: "org-b" }); // Error: FORBIDDEN