Access Control Tutorial

Open inAnthropic

In this tutorial you will create a second user with read-only access to a database. By the end you will have:

  1. A database with data in it
  2. A new user (alice) who can read — but not write — that database
  3. Verified that permission enforcement works

Time: ~10 minutes
Prerequisites: TerminusDB running on localhost:6363 (Install guide →)

TerminusDB must be running

If you have trouble connecting, see Troubleshooting Connection Failures and Authentication Errors.

Step 1 — Create a database with data

First, create a database and insert a document so we have something to protect:

# Create the database
curl -s -u admin:root -X POST "http://localhost:6363/api/db/admin/MyDatabase" \
  -H "Content-Type: application/json" \
  -d '{"label": "MyDatabase", "comment": "Access control tutorial"}'

# Insert a document
curl -s -u admin:root -X POST \
  "http://localhost:6363/api/document/admin/MyDatabase?author=admin&message=Add+document&raw_json=true" \
  -H "Content-Type: application/json" \
  -d '{"@id": "terminusdb:///data/jane", "name": "Jane Smith", "email": "jane@example.com"}'

Verify the document is accessible:

curl -s -u admin:root \
  "http://localhost:6363/api/document/admin/MyDatabase?raw_json=true&id=terminusdb:///data/jane"

You should see Jane's document returned as JSON.

Step 2 — Create a new user

Create a user called alice with a password:

curl -s -u admin:root -X POST http://localhost:6363/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "alice", "password": "alice-secret"}'

Expected response:

Example: JSON
"terminusdb://system/data/User/alice"

Verify the user exists:

curl -s -u admin:root http://localhost:6363/api/users/alice

Step 3 — Grant read-only access

Grant the built-in "Consumer Role" (read-only) to alice on MyDatabase:

curl -s -u admin:root -X POST http://localhost:6363/api/capabilities \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "grant",
    "scope_type": "database",
    "scope": "admin/MyDatabase",
    "user": "alice",
    "roles": ["Consumer Role"]
  }'

The Consumer Role includes three actions: class_frame, instance_read_access, and schema_read_access. This means alice can read documents and schema but cannot insert, update, or delete anything.

Step 4 — Verify read access works

Authenticate as alice and read the document:

curl -s -u alice:alice-secret \
  "http://localhost:6363/api/document/admin/MyDatabase?raw_json=true&id=terminusdb:///data/jane"

You should see Jane's document — alice has read access.

Step 5 — Verify write access is denied

Now try to insert a document as alice:

curl -s -u alice:alice-secret -X POST \
  "http://localhost:6363/api/document/admin/MyDatabase?author=alice&message=Attempt+write&raw_json=true" \
  -H "Content-Type: application/json" \
  -d '{"@id": "terminusdb:///data/bob", "name": "Bob Jones", "email": "bob@example.com"}'

You should receive a 403 Forbidden error:

Example: JSON
{
  "@type": "api:ErrorResponse",
  "api:message": "Insufficient capabilities for this operation",
  "api:status": "api:forbidden"
}

This confirms that alice cannot write — the access control is working correctly.

Step 6 — Upgrade to write access (optional)

If you want to give alice write access, create a custom writer role and grant it:

# Create a writer role
curl -s -u admin:root -X POST http://localhost:6363/api/roles \
  -H "Content-Type: application/json" \
  -d '{
    "name": "writer",
    "action": [
      "commit_write_access",
      "instance_read_access",
      "instance_write_access",
      "schema_read_access",
      "class_frame"
    ]
  }'

# Grant the writer role to alice on MyDatabase
curl -s -u admin:root -X POST http://localhost:6363/api/capabilities \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "grant",
    "scope_type": "database",
    "scope": "admin/MyDatabase",
    "user": "alice",
    "roles": ["writer"]
  }'

Now alice can insert documents:

curl -s -u alice:alice-secret -X POST \
  "http://localhost:6363/api/document/admin/MyDatabase?author=alice&message=Add+Bob&raw_json=true" \
  -H "Content-Type: application/json" \
  -d '{"@id": "terminusdb:///data/bob", "name": "Bob Jones", "email": "bob@example.com"}'

Step 7 — Clean up (optional)

Revoke access and delete the user:

# Revoke the consumer role
curl -s -u admin:root -X POST http://localhost:6363/api/capabilities \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "revoke",
    "scope_type": "database",
    "scope": "admin/MyDatabase",
    "user": "alice",
    "roles": ["Consumer Role"]
  }'

# Delete the user
curl -s -u admin:root -X DELETE http://localhost:6363/api/users/alice

What you learned

  • Users are identities that authenticate with username/password
  • Roles are named sets of actions (the built-in Consumer Role is read-only)
  • Capabilities link users to roles on specific resources (databases or organisations)
  • The /api/capabilities endpoint grants and revokes access
  • Permissions are enforced — unauthorized operations return 403

Next steps

Was this helpful?