Token scopes
Curiosity Workspace issues three kinds of bearer tokens. Choosing the right one — and scoping it tightly — is the single biggest lever for getting external integration security right.
| Token type | Issued by | Used by | Scope dimension |
|---|---|---|---|
| User session JWT | the login flow (password, SSO, SAML) | the built-in front-end and custom interfaces | the user's permissions (ReBAC) |
| API token | Settings → API Tokens | data connectors, CLI scripts, CI jobs | named scopes (ingestion, read, …) |
| Endpoint token | Settings → Custom Endpoints → Tokens | external systems calling specific endpoints | path-scoped to one or more endpoints |
All three are sent the same way:
Authorization: Bearer <token>
User session JWT
Issued automatically when a user signs in. Carries the user's UID and team memberships. The graph and search engines use it to compute permission filters via the ReBAC model.
You should rarely need to handle session JWTs explicitly. The built-in chat, search, and graph views attach them automatically; custom interfaces written with Tesserae do the same.
If you're scripting against a Workspace as a specific user (for example, in a test), call /api/login/create with credentials and reuse the returned token.
API tokens
Long-lived tokens issued from Settings → API Tokens. Each token is bound to one or more scopes. A scope is a logical capability — not a path — and is enforced by the controllers behind the matching endpoints.
Recommended scope assignments
| Use case | Recommended scopes | Why |
|---|---|---|
| Data connector that only writes data | ingestion |
Lets the connector create/update nodes and edges. No read access to other tenants' data. |
| Read-only export script | read, search |
Can run graph queries and searches but cannot mutate. |
| Backup job that snapshots and restores | admin:backup |
Limited admin capability without full admin rights. |
| Operator script triaging tasks | admin:tasks |
Limited admin capability for scheduled-task management. |
| CI smoke test on staging | read, endpoints:run |
Lets CI hit custom endpoints during deploy validation. |
Least-privilege recipes
Ingestion-only connector
- Create a token named after the connector (
crm-sync-connector). - Grant the
ingestionscope. Do not grantadminorreadon other types. - Store in your secret manager; rotate on a schedule.
- If the connector also needs to ingest ACLs (
RestrictAccessTo*), add theingestion:aclscope. ===
Read-only export to a data warehouse
- Create a token named after the consumer (
bi-warehouse-export). - Grant
readandsearch. - The token will only return content the workspace would show to the system — it does not bypass per-user ACLs. If you need per-user data, use endpoint tokens with
CreateSearchAsUserAsync. ===
External system calling one custom endpoint
Use an endpoint token (next section) instead of an API token. Endpoint tokens are path-scoped and cannot be repurposed.
Endpoint tokens
Issued per custom-endpoint or per group of endpoints. They are the right tool when an external system needs to call a specific endpoint and nothing else.
Properties:
- Path-scoped: a token valid for
/api/endpoints/run/similar-ticketscannot call/api/endpoints/run/admin-rebuild-index. - Optionally act-as a specific user, in which case
CurrentUserinside the endpoint is that user and ReBAC applies. - Issued from the endpoint editor; rotated independently of API tokens.
Choosing between API and endpoint tokens
| Question | Use API token | Use endpoint token |
|---|---|---|
| Does the caller need access to many resources (graph, search, ingestion)? | yes | — |
| Does the caller only need to invoke one or a few endpoints? | — | yes |
| Does the caller need to run as a specific Workspace user? | — | yes |
| Will the credential be embedded in a third-party system you don't control? | — | yes (smaller blast radius) |
Rotation and revocation
- Rotation: create the new token, deploy it to consumers, then revoke the old one. Workspace tokens are stateless JWTs, so revocation lists are checked on every call.
- Compromise response: from Settings → API Tokens, click Revoke. The token is rejected starting on the next request.
- JWT key rotation: setting a new
MSK_JWT_KEYinvalidates every outstanding token. Use this only when responding to a key-material compromise; you'll need to reissue all tokens afterward.
Sending tokens correctly
Always use the Authorization: Bearer … header. Avoid query-string tokens — they leak into proxy logs and browser histories.
curl -X POST "https://workspace.example.com/api/endpoints/run/similar-tickets" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"screen flicker"}'
Errors
| HTTP status | Meaning | What to do |
|---|---|---|
401 Unauthorized |
Missing or malformed token | Add the Authorization header. |
401 Unauthorized with WWW-Authenticate: Bearer error="invalid_token" |
Signature invalid (wrong MSK_JWT_KEY) or expired |
Re-issue the token. |
403 Forbidden |
Token is valid but missing the scope or path required | Re-issue with the correct scope or endpoint path. |
404 Not Found on a custom endpoint |
Endpoint doesn't exist, or token's path scope excludes it | Check the endpoint name and the token's allowed paths. |
See the full list in Error codes.
Related pages
- API Usage — the request shape and auth flow.
- Custom Endpoints — how to write the server side that consumes these tokens.
- Security — the surrounding operational practices.
Referenced by
- multimodal-tutorial
- connector-templates
- connectors
- ingestion-pipelines
- pipeline-orchestration
- migration-from-elasticsearch-vector-db-langchain
- api-overview
- api-usage
- custom-endpoints
- build-your-first-enterprise-ai-app
- developer-prerequisites
- embeddings-api
- error-codes
- metrics-reference
- rest-api
- sdk-csharp