Skip to main content
Version: v5

Users & Roles

Harper uses a Role-Based Access Control (RBAC) framework to manage access to Harper instances. Each user is assigned a role that determines their permissions to access database resources and run operations.

Roles​

Role permissions in Harper are divided into two categories:

Database Manipulation — CRUD (create, read, update, delete) permissions against database data (tables and attributes).

Database Definition — Permissions to manage databases, tables, roles, users, and other system settings. These are restricted to the built-in super_user role.

Built-In Roles​

RoleDescription
super_userFull access to all operations and methods. The admin role.
structure_userAccess to create and delete databases and tables. Can be set to true (all databases) or an array of database names (specific databases only).

User-Defined Roles​

Admins (super_user users) can create custom roles with explicit permissions on specific tables and attributes.

  • Unless a user-defined role has super_user: true, all permissions must be defined explicitly.
  • Any table or database not included in the role's permission set will be inaccessible.
  • describe operations return metadata only for databases, tables, and attributes that the role has CRUD permissions for.

Permission Structure​

When creating or altering a role, you define a permission object:

{
"operation": "add_role",
"role": "software_developer",
"permission": {
"super_user": false,
"database_name": {
"tables": {
"table_name1": {
"read": true,
"insert": true,
"update": true,
"delete": false,
"attribute_permissions": [
{
"attribute_name": "attribute1",
"read": true,
"insert": true,
"update": true
}
]
},
"table_name2": {
"read": true,
"insert": true,
"update": true,
"delete": false,
"attribute_permissions": []
}
}
}
}
}

Operation Permissions​

The operations field in a permission object restricts which Operations API calls this role can make. When set, it acts as a two-gate check:

  1. Only listed operations are reachable — any unlisted operation is denied regardless of table CRUD permissions.
  2. For data operations that pass gate one, table-level CRUD permissions still apply as normal.

Operations normally restricted to super_user can be selectively granted by including them in the list. If operations is not set, the role can call any non-super_user operation, subject to table CRUD permissions.

List an aliased operation by its canonical name. create_database, drop_database, describe_schema, search_by_hash, add_component, package_component, deploy_component, and delete_files_before each grant their legacy spelling too (create_schema, drop_schema, describe_database, search_by_id, add_custom_function_project, package_custom_function_project, deploy_custom_function_project, delete_records_before), but a list that names only the legacy spelling grants neither.

A few super_user operations cannot be granted by listing them: the secrets-store operations, the OIDC trust-policy operations, get_deployment_payload, the managed-backup operations (create_backup, list_backups, verify_backup, delete_backup, purge_backups, restore_backup), get_backup, read_transaction_log, and the legacy catchup. A role can still store these names, since add_role and alter_role check only that each entry is a known operation or group name, but a call to one from that role is refused. When auditing roles, don't read a listed name as a grant.

Changed in: v5.3.0

An operation the list omits is denied whatever else the role carries — the list is checked ahead of every other permission on the role. Earlier v5 releases let table DDL and SQL around it; both now go through it.

Earlier releases also let a role list deploy_component, add_component, drop_component, package_component, set_component_file, set_custom_function, drop_custom_function, drop_custom_function_project, restart_service, set_configuration, get_status, set_status, clear_status, install_node_modules, delete_files_before, delete_audit_logs_before, delete_transaction_logs_before, cleanup_orphan_blobs, search_jobs_by_start_date, and registration_info but refused the call, whatever else the role carried. They are granted as listed now. catchup, which earlier releases granted to a role that listed it, no longer can be.

So grant by listing, and build a role up rather than trying to narrow super_user — add_role and alter_role reject super_user or cluster_user set to true alongside any other key. A role that maintains one database's tables and queries them with SQL:

{
"operation": "add_role",
"role": "orders_maintainer",
"permission": {
"operations": ["sql", "create_table", "drop_table"],
"structure_user": ["orders_db"],
"orders_db": {
"tables": {
"orders": {
"read": true,
"insert": true,
"update": false,
"delete": false,
"attribute_permissions": []
}
}
}
}
}

sql has to be listed or the role cannot run SQL at all. Listing it grants the interface, not the data: the statement is still checked against the table permissions above, so this role can SELECT and INSERT on orders and nothing else. That check is what separates the read_only and standard_user groups below, which both include sql.

create_table and drop_table have to be listed too, and structure_user then limits them to orders_db. create_database and drop_database additionally require structure_user: true.

The value must be an array of strings; a non-array value is rejected on write. A role that already holds one — a pre-5.0 role that granted a database named operations, before the key became reserved — can stop the instance loading its user cache (harper#2194).

Permission Groups

Groups expand to a predefined set of operations and can be mixed with individual operation names:

  • read_only — Search, SQL SELECT, describe, and monitoring operations. No data modification. Operations: search, search_by_conditions, search_by_hash, search_by_id, search_by_value, sql, describe_all, describe_schema, describe_database, describe_table, user_info, get_job, get_analytics, list_metrics, describe_metric

  • standard_user — Everything in read_only plus full data manipulation and bulk load. Does not include any super_user-restricted operations, schema DDL (create_attribute), or token management. Additional operations beyond read_only: insert, update, upsert, delete, csv_data_load, csv_file_load, csv_url_load, import_from_s3

  • agent — Drive the built-in agent without full super_user. Operations: agent_prompt, get_agent_session, list_agent_sessions, cancel_agent_run, approve_agent_action. set_agent_config is deliberately excluded, so a delegated role cannot change the agent's model or approval policy. Read the agent section's security warning before granting this: the session reads are not caller-scoped, and a prompt directs tools that run at process privilege

Example: read-only role

{
"operation": "add_role",
"role": "read_only_analyst",
"permission": {
"operations": ["read_only"],
"orders_db": {
"tables": {
"orders": {
"read": true,
"insert": false,
"update": false,
"delete": false,
"attribute_permissions": []
}
}
}
}
}

Example: full data access + targeted admin operations

{
"operation": "add_role",
"role": "ops_engineer",
"permission": {
"operations": ["standard_user", "get_configuration", "system_information"],
"orders_db": {
"tables": {
"orders": {
"read": true,
"insert": true,
"update": true,
"delete": true,
"attribute_permissions": []
}
}
}
}
}

Table Permissions​

Each table entry defines CRUD access:

{
"table_name": {
"read": boolean, // Access to read from this table
"insert": boolean, // Access to insert data
"update": boolean, // Access to update data
"delete": boolean, // Access to delete rows
"attribute_permissions": [
{
"attribute_name": "attribute_name",
"read": boolean,
"insert": boolean,
"update": boolean
// Note: "delete" is not an attribute-level permission
}
]
}
}

Important Rules​

Table-level:

  • If a database or table is not included in the permissions, the role has no access to it.
  • If a table-level CRUD permission is false, setting the same CRUD permission to true on an attribute returns an error.

Attribute-level:

  • If attribute_permissions is a non-empty array, only the listed attributes are accessible (plus the table's hash attribute — see below).
  • If attribute_permissions is empty ([]), attribute access follows the table-level CRUD permissions.
  • If any non-hash attribute is given CRUD access, the table's hash_attribute (primary key) automatically receives the same access, even if not explicitly listed.
  • Any attribute not explicitly listed in a non-empty attribute_permissions array has no access.
  • DELETE is not an attribute-level permission. Deleting rows is controlled at the table level.
  • The __createdtime__ and __updatedtime__ attributes managed by Harper can have read permissions set; other attribute-level permissions for these fields are ignored.

Filter side-channel for read-restricted attributes​

note

Setting read: false on an attribute prevents the value from appearing in response bodies. However, an indexed attribute can still be used as a filter predicate on an exported Resource's generated query routes, including REST and GraphQL. For example, GET /Table/?salary=95000 returns the matching rows without the salary field, and the number of results reveals whether any records hold that exact value. Range predicates can similarly enable binary-search enumeration of the restricted column without ever returning a value directly. If preventing this inference is a requirement, do not expose generated query routes for the table. Force callers through a custom resource that rejects or ignores filter conditions on read: false attributes.

Role-Based Operation Restrictions​

Databases and Tables​

OperationRestricted to Super User
describe_all
describe_database
describe_table
create_databaseX
drop_databaseX
create_tableX
drop_tableX
create_attribute
drop_attributeX

NoSQL Operations​

OperationRestricted to Super User
insert
update
upsert
delete
search_by_hash
search_by_value
search_by_conditions

SQL Operations​

OperationRestricted to Super User
select
insert
update
delete

Bulk Operations​

OperationRestricted to Super User
csv_data_load
csv_file_load
csv_url_load
import_from_s3

Users and Roles​

OperationRestricted to Super User
list_rolesX
add_roleX
alter_roleX
drop_roleX
list_usersX
user_info
add_userX
alter_userX
drop_userX

Clustering​

OperationRestricted to Super User
cluster_set_routesX
cluster_get_routesX
cluster_delete_routesX
add_nodeX
update_nodeX
cluster_statusX
remove_nodeX
configure_clusterX

Components​

OperationRestricted to Super User
get_componentsX
get_component_fileX
set_component_fileX
drop_componentX
add_componentX
package_componentX
deploy_componentX

Registration​

OperationRestricted to Super User
registration_info
get_fingerprintX
set_licenseX

Jobs​

OperationRestricted to Super User
get_job
search_jobs_by_start_dateX

Logs​

OperationRestricted to Super User
read_logX
read_transaction_logX
delete_transaction_logs_beforeX
read_audit_logX
delete_audit_logs_beforeX

Utilities​

OperationRestricted to Super User
delete_records_beforeX
export_localX
export_to_s3X
system_informationX
restartX
restart_serviceX
get_configurationX

Token Authentication​

OperationRestricted to Super User
create_authentication_tokens
refresh_operation_token

Troubleshooting: "Must execute as User"​

If you see the error Error: Must execute as <<username>>, it means Harper was installed as a specific OS user and must be run by that same user. Harper stores files natively on the operating system and only allows the Harper executable to be run by a single user — this prevents file permission issues and keeps the installation secure.

To resolve: run Harper with the same OS user account used during installation.