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:
| Method | Best for | Lifetime | Initiator |
|---|---|---|---|
| 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 person | Short-lived, re-minted from the client secret | A member with ws:manage_oauth_clients (Owner by default) enables M2M on an application |
| Workspace API key | Server-to-server scripts and integrations (cron jobs, ETL pipelines, internal tools) | Never expires unless you pick an expiry | Any workspace member, in an organization with the api feature enabled |
| MCP token | LLM tool clients (Claude Desktop, Cursor, custom MCP-aware agents) | Short-lived bearer with auto-refresh | User 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: identityoffline_access: get a refresh tokenmcp:tools,mcp:read,mcp:write: declared, and shown on the consent screen for MCP clientsmcp: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
- Settings → Developer → API Keys → Create API Key
Pick the workspace the key should access (one workspace per key). Only workspaces whose organization has the
apifeature enabled are listed. - 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.
- 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. - Set an expiry
30 days, 90 days, 1 year, or Never. The default is Never, so pick an expiry explicitly and rotate proactively.
- 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.