Skip to main content

API key scopes

A scope is one permission on one API key. Each key carries a set of them, and the set decides which surfaces the bearer reaches: the contract namespaces on /rpc/*, the SSE endpoint, and the OpenAI-compatible /v1/* endpoints. Two mint paths issue keys from this same vocabulary — the apiKeys.create RPC (cookie-auth only, used by the web Settings tab) and ethos api-key create on the CLI.

Source

ApiKeyScopeSchema is defined in packages/web-contracts/src/schemas.ts.

Scope table

ScopeGates
sessions:readRead access to sessions.list and sessions.get.
sessions:writeWrite access to sessions.fork, sessions.delete, and sessions.update.
chatThe whole OpenAI-compatible surface: /v1/models and /v1/chat/completions. Asserted once at the /v1 mount, so it covers every route under it.
chat:sendAccess to chat.send and chat.abort on /rpc/*.
personalities:readRead access to personalities.list, personalities.get, personalities.characterSheet, and personality skills read methods.
memory:readRead access to memory.list and memory.get.
memory:writeWrite access to memory.write. Implies memory:read at the server level.
tools:approveAccess to tools.approve and tools.deny for the tool approval workflow.
events:subscribeAccess to the SSE endpoint (/sse/sessions/:sessionId). Required for EventStream.

chat vs chat:send

Two scopes read as "chat" and neither implies the other.

  • chat gates /v1/*, the OpenAI-compatible surface. Grant it to Cursor, Aider, Open WebUI, and the OpenAI Python/Node SDKs.
  • chat:send gates the chat.send and chat.abort RPC procedures on /rpc/*. Grant it to a Mission Control built on @ethosagent/sdk.
  • A key that drives both needs both listed.
  • ethos api-key create defaults --scopes to chat, because /v1/* is the surface the CLI mints keys for. The web UI has no default — pick the scopes in the create form.

ApiKeyMetadata

When you create or list keys, each key returns an ApiKeyMetadata object:

FieldTypeDescription
idstringUnique key identifier.
prefixstringFirst characters of the key (e.g. esk_abc...) for identification without exposing the secret.
namestringHuman-readable label set at creation.
scopesApiKeyScope[]Scopes granted to this key.
allowedOriginsstring[]Origins permitted to use this key (CORS enforcement).
createdAtstringISO-8601 creation timestamp.
lastUsedstring | nullISO-8601 timestamp of last use, or null if never used.
revokedAtstring | nullISO-8601 timestamp of revocation, or null if active.

Creating a key

The apiKeys namespace is restricted to cookie-auth. A bearer token cannot mint new keys.

import { EthosClient } from '@ethosagent/sdk';

// Cookie-auth -- browser context
const client = new EthosClient({ baseUrl: 'http://localhost:2400' });

const { secret, key } = await client.rpc.apiKeys.create({
name: 'my-dashboard',
scopes: ['sessions:read', 'chat:send', 'events:subscribe'],
allowedOrigins: ['https://dashboard.example.com'],
});

// `secret` is the plaintext key -- shown once, never again.
// `key` is the ApiKeyMetadata for the new key.

The CLI mints from the same vocabulary, and rejects a scope that is not in the table above:

ethos api-key create --name "openai-clients" --scopes chat

Minimum viable scope set

A Mission Control that sends messages and renders responses needs at minimum:

  • chat:send -- to start turns
  • events:subscribe -- to receive streamed responses
  • sessions:read -- to list and fetch session history

An OpenAI-compatible client needs exactly one scope: chat.

See also