Authentication

OAuth, API keys, MCP tokens — when to use each.

Dalea offers four authentication paths for programmatic access. Each is optimised for a different scenario:

MethodBest forLifetimeInitiator
OAuth 2.1 (PKCE)Apps acting on behalf of an end user (browser apps, desktop apps that already speak OAuth)Long-lived (refresh-token)User clicks Authorise
OAuth 2.1 client credentials (M2M)Services with their own standing identity (a LIMS sync, a pipeline), runs as a dedicated service account, not a personShort-lived, re-minted from the client secretA member with ws:manage_oauth_clients (Owner by default) enables M2M on an application
Workspace API keyServer-to-server scripts and integrations (cron jobs, ETL pipelines, internal tools)Never expires unless you pick an expiryAny workspace member, in an organization with the api feature enabled
MCP tokenLLM tool clients (Claude Desktop, Cursor, custom MCP-aware agents)Short-lived bearer with auto-refreshUser clicks Authorise (OAuth-flavoured)

Pick whichever matches the actor. If a person is in front of the screen, use OAuth or MCP. If a script runs without anyone watching, use an API key — or, when the integration deserves its own identity instead of borrowing a person's, an M2M application.

OAuth 2.1 — apps acting as a user

Use when your application authenticates end users and acts on their behalf. Standard OAuth 2.1 flow:

┌──── Your app ────┐                ┌──── Dalea ────┐
│                  │  /authorize    │               │
│   Browser ──────────────────────► │  consent page │
│                  │                │               │
│                  │  ?code=...     │               │
│   Browser ◄─────────────────────  │               │
│                  │                │               │
│   Server  ──────────────────────► │  /token       │
│                  │  exchange code │               │
│                  │  ◄──────────── │  access+refresh
└──────────────────┘                └───────────────┘

Available scopes:

  • openid profile email: identity
  • offline_access: get a refresh token
  • mcp:tools, mcp:read, mcp:write: declared, and shown on the consent screen for MCP clients
  • mcp:code-exec: required to call the two code-execution MCP tools

What an OAuth or MCP token may actually do comes from the workspace role the user grants at authorization, not from the mcp:* scopes. mcp:code-exec is the one scope enforced on its own: a token without it is refused by the code-execution tools.

Register the application in Settings → Workspaces → your workspace → Applications → New Application. You'll get a client_id and, for confidential clients, a client_secret; the secret stays on your server only.

OAuth 2.1 client credentials — machine-to-machine

When no user is involved at all, a confidential application with machine-to-machine access enabled can mint tokens directly from its client_id + client_secret (the standard client_credentials grant). Behind the scenes the application is backed by a dedicated service account — a login-disabled machine identity holding the application's workspace role, so permissions and audit trails work exactly as for a human member, without consuming a member seat.

The SDK + OAuth guide walks through both this flow and PKCE with runnable code.

Workspace API keys — for scripts

When a script runs without a user, an API key is the right choice.

Creating one

  1. Settings → Developer → API Keys → Create API Key

    Pick the workspace the key should access (one workspace per key). Only workspaces whose organization has the api feature enabled are listed.

  2. Pick a scope

    Three choices: Self (your current role), one of the workspace roles whose permissions you already hold, or Custom API Scope. Owner is never offered in the role list. A key can never exceed the permissions of the person who created it.

  3. Optional: narrow the permissions

    With Custom API Scope you tick individual workspace actions (ws:view_documents, ws:edit_data, and so on). Actions that another selection implies are ticked for you and can't be unticked. Permissions are workspace-wide: there is no per-environment or per-table key scoping.

  4. Set an expiry

    30 days, 90 days, 1 year, or Never. The default is Never, so pick an expiry explicitly and rotate proactively.

  5. Copy the key once

    Dalea displays the key string exactly once. Store it in your secret manager immediately — there's no way to retrieve it later.

Using a key

Send it on the X-API-Key header. The key is bound to its workspace at creation, so there's nothing else to scope:

curl https://dalea.app/api/v1/documents \
  -H "X-API-Key: $DALEA_API_KEY"
import requests

resp = requests.get(
    "https://dalea.app/api/v1/documents",
    headers={"X-API-Key": api_key},
)
resp.raise_for_status()
for doc in resp.json()["documents"]:
    print(doc["title"])
const resp = await fetch('https://dalea.app/api/v1/documents', {
  headers: { 'X-API-Key': apiKey },
});
const { documents } = await resp.json();

The official Dalea SDK does this for you — set the DALEA_API_KEY environment variable and construct a client.

Revoking

Same Settings → Developer page: Revoke on the key's row. Revocation is immediate. If a key is compromised, revoke it first, then issue a new one, never the other way round.

MCP tokens — for LLM tool clients

If you're building an MCP-aware client (a Claude Desktop alternative, a custom agent), use the MCP OAuth flow. It's structurally OAuth 2.1 but tokens are short-lived and auto-refresh; access is bound to one workspace and one role.

See MCP for tool builders for the full flow and example client.

Choosing per scenario

A nightly script that pulls a CSV of new results
Workspace API key with a Viewer-level scope, in the workspace holding the data.
An internal web app where each scientist views their own data
OAuth — each user signs in with their own Dalea account.
A LIMS sync that must outlive any one employee
M2M application (client credentials) — its service account is the actor, not a person’s key.
A Slack bot that posts when a new result batch is recorded
Workspace API key with a custom scope covering data reads and document reads.
A custom Claude Desktop alternative
MCP OAuth flow.
A Cursor instance you want to use as a co-analyst
MCP OAuth flow — same as Claude Desktop.
A Python notebook running on a researcher's laptop
Workspace API key created by that researcher, inheriting their own role.

Security notes

  • Never commit secrets. Use environment variables and a secret manager.
  • Scope down. Don't hand a key your full role when a Custom API Scope with two or three actions would do.
  • Rotate. Keys never expire by default. Pick 90 days at creation and have a rotation job in your secret manager rather than rotating by hand.
  • Audit. Writes made with a key are recorded with the actor the key represents, the auth method (api_key), the action and, where required, a change reason. Reads are not audited. See Audit logging.

What's next