In this tutorial you will create a second user with read-only access to a database. By the end you will have:
- A database with data in it
- A new user (
alice) who can read — but not write — that database - 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:
"terminusdb://system/data/User/alice"Verify the user exists:
curl -s -u admin:root http://localhost:6363/api/users/aliceStep 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:
{
"@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/aliceWhat 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/capabilitiesendpoint grants and revokes access - Permissions are enforced — unauthorized operations return 403
Next steps
- Access Control Reference — Full API reference for all endpoints and actions
- JavaScript Client Access Control — Manage access control programmatically
- Tutorial Source Code — Full JavaScript example with custom roles and multiple users