API & Platform
Authentication, tenancy & authorization
Every request is a scoped principal acting inside a tenant. The platform enforces that scope on every read and every write — not as a filter after the fact, but as a bound context the store layer cannot escape.
Principals & API keys
A principal is a human user, a service identity, or the app sidecar itself. API keys are tenant-scoped and carry RBAC scopes (e.g. datasets:read, apps:write, builder:plan).
Keys live in ~/.config/lace/credentials.toml locally (mode 0600) or in ECS/Secrets Manager in cloud. Env var LACE_API_KEY overrides the file — useful in CI.
| Surface | How you authenticate |
|---|---|
| Browser / frontend | SSO/OIDC via the LACE auth gateway (session cookie → JWT) |
| CLI & REST API | Authorization: Bearer <api_key> |
| App sidecar → platform | Sidecar-injected token for its own tenant (via SidecarActivator) |
Introspect with GET /v1/auth/whoami (or lace-app auth whoami) — returns tenant, principal, and granted scopes.
Tenancy — the bound context
Tenancy is not a query param you can mistype. After auth, the request is bound with bind_store_tenant(tenant_id) and every store call — AppDataService, retrieval, KG, pipeline, agent sessions — inherits that binding.
The lace-app-sdk's AppDataService never needs a tenant arg for reads/writes because the bound context already carries it. Agents' tenant_id="default" placeholder in AgentDefinition is always substituted with the real request tenant at turn time.
RBAC scopes
Top-level gates. Each route declares the scope it requires; the auth middleware rejects before the handler runs.
| Scope | Grants |
|---|---|
apps:read / apps:write | List / create / publish apps and releases |
datasets:read / datasets:write | Connect sources, trigger sync, read indexed content |
search:query | Enterprise search & RAG retrieval |
kg:read / kg:write | Query entities / propose or accept assertions |
agents:run | Start sessions, send turns, invoke tools |
builder:plan | Drive the App Builder architect |
admin:* | Tenant-admin operations (members, budgets, retention) |
Resource ACLs — beneath RBAC
RBAC gets you through the route gate; resource ACLs decide which rows you see. Two places:
- Dataset / document ACLs — permission snapshots captured at sync time flow forward to retrieval. Enterprise search enforces them in SQL (prefilter) and in the Python finalize — facet counts never leak restricted entities (
src/lace/domain/enterprise_search/acl.py). - AppData ACLs — declared via
AppDataPermissionson a collection; evaluated per-record byAppDataService.
An identity without access never reaches the resource — as opposed to reaching it and having the result filtered afterward.
Governance — budgets, approvals, audit
Beyond auth, the platform enforces budgets & usage limits (per-model, per-agent, per-tenant), approval gates (tool-level approval_required pauses the loop with waiting_approval), and audit (structured logs + OpenTelemetry traces with per-call model attribution).
See governance & security and observability.
Practically
- Create an API key in the LACE console (tenant → settings → API keys) or via
POST /v1/auth/api-clients(admin). - Store it with
lace-app auth login --api-url https://api.laceplatform.com --api-key $KEY. - Use
LACE_API_KEYin CI — no file needed. - Never check keys into the app repo — use
lace-app secrets setfor app-scoped secrets.
Next: REST API overview or governance.