GenosDB’s Security Manager implements a comprehensive Role-Based Access Control (RBAC) system that enforces granular permissions across the distributed network using cryptographic signatures and decentralized role storage.
Overview
The RBAC system provides:
Customizable role hierarchy (superadmin, admin, user, guest)
Granular permissions (read, write, delete, link, sync, assignRole)
Cryptographic identity tied to Ethereum addresses
Decentralized role storage in the graph itself
Automatic enforcement via middleware on all operations
Architecture Components
1. Identity Management
Every user is identified by a cryptographic Ethereum wallet :
const db = await gdb ( 'mydb' , {
rtc: true ,
sm: {
superAdmins: [ '0x1234...' , '0x5678...' ] // Ethereum addresses
}
});
const sm = db . sm ; // Access Security Manager
Identity Creation Methods:
WebAuthn (Recommended)
Mnemonic Phrase
// Register new user with biometric/hardware key
const result = await sm . startNewUserRegistration ();
// User creates mnemonic backup
// Protect with WebAuthn
await sm . protectCurrentIdentityWithWebAuthn ();
// Future logins use biometrics
await sm . loginCurrentUserWithWebAuthn ();
WebAuthn provides passwordless, phishing-resistant security using biometrics or FIDO2 keys.
// Create new identity with mnemonic
const { mnemonic , address } = await sm . startNewUserRegistration ();
// Save mnemonic securely (user responsibility)
// Later recovery/login
await sm . loginOrRecoverUserWithMnemonic ( mnemonic );
Users must safely store their mnemonic phrase. Loss of mnemonic means permanent loss of identity.
2. Role Hierarchy
Default role hierarchy (customizable):
const DEFAULT_ROLES = {
superadmin: {
can: [ 'read' , 'write' , 'delete' , 'link' , 'sync' , 'assignRole' , 'publish' ]
},
admin: {
can: [ 'read' , 'write' , 'delete' , 'link' , 'sync' , 'publish' ]
},
manager: {
can: [ 'read' , 'write' , 'link' , 'sync' , 'publish' ]
},
user: {
can: [ 'read' , 'write' , 'link' , 'sync' ]
},
guest: {
can: [ 'read' , 'sync' ]
}
};
Custom Roles:
const db = await gdb ( 'mydb' , {
rtc: true ,
sm: {
superAdmins: [ '0x...' ],
customRoles: {
moderator: {
can: [ 'read' , 'write' , 'delete' , 'sync' ] // Can delete but not assign roles
},
viewer: {
can: [ 'read' ] // Read-only, no sync
}
}
}
});
3. In-Graph Role Storage
Roles are stored as nodes within the GDB graph itself:
// Role assignment creates a node
user : 0x1234567890abcdef1234567890abcdef12345678
{
role : 'admin' ,
assignedBy : '0xabcdef...' ,
assignedAt : 1709582400000 ,
expiresAt : null // optional expiration
}
Roles are distributed and eventually consistent like all data in GenosDB, enabling true decentralized access control.
Permission Enforcement
Outgoing Operation Signing
When an authenticated user performs a database modification, the operation is automatically signed:
// User writes data
await db . put ({ title: 'My Note' , content: 'Hello' });
// Behind the scenes, SM signs the operation
const signedOperation = {
type: 'upsert' ,
id: 'node-123' ,
value: { title: 'My Note' , content: 'Hello' },
timestamp: { physical: 1709582400000 , logical: 0 },
signature: '0x...' , // ECDSA signature
originEthAddress: '0x1234...' // Sender's address
};
Incoming Operation Verification
When a peer receives an operation, the SM performs critical checks:
Verify Signature
Cryptographically verify the signature matches the operation content and sender’s address const isValid = verifySignature (
operationHash ,
operation . signature ,
operation . originEthAddress
);
if ( ! isValid ) {
// Discard invalid operation
return ;
}
Resolve Permissions
Look up the sender’s role in the local graph const userNode = await db . get ( `user: ${ operation . originEthAddress } ` );
const role = userNode ?. value ?. role || 'guest' ;
Authorize Action
Check if the role has permission for the requested action const action = mapOperationToAction ( operation . type );
// operation.type 'upsert' -> action 'write'
const hasPermission = can ( role , action );
if ( ! hasPermission ) {
// Silently filter out unauthorized operation
return ;
}
Apply Operation
Only verified, authorized operations are applied to the local graph // Safe to apply
this . graph . set ( operation . id , operation . value );
Zero-Trust Enforcement Every peer independently enforces the network’s rules. Invalid operations are silently filtered out, preventing unauthorized data from entering the local state.
Role Assignment
Only users with assignRole permission (typically superadmins) can change roles:
// Check current user's role
const myRole = await sm . getCurrentUserRole ();
console . log ( myRole ); // 'superadmin'
// Assign role to another user
if ( myRole === 'superadmin' ) {
await sm . assignRole (
'0xnewuser...' , // Target user's address
'admin' , // New role
null // Optional expiration timestamp
);
}
What happens:
Creates/updates user:0xnewuser... node with role: 'admin'
Signs the operation with superadmin’s private key
Broadcasts to all peers
Peers verify signature and superadmin authority
Role update is applied across the network
Permission Checks in Application Code
Declarative Permission Check
// Throws error if permission denied
try {
await sm . executeWithPermission ( 'delete' );
await db . remove ( nodeId );
} catch ( error ) {
console . error ( 'Permission denied:' , error . message );
}
Manual Permission Check
const userRole = await sm . getCurrentUserRole ();
if ( can ( userRole , 'write' )) {
// User has write permission
await db . put ( data );
} else {
// Show read-only UI
}
Helper Function
function can ( role , action ) {
const roleConfig = ROLES [ role ];
return roleConfig ?. can . includes ( action ) || false ;
}
Security Flow Example
Scenario: User Tries to Delete a Node
Scenario: Admin Successfully Deletes Node
Superadmin Authority
Superadmins have special authority:
Static Source of Truth:
const db = await gdb ( 'mydb' , {
sm: {
superAdmins: [ '0xALICE...' , '0xBOB...' ] // Immutable during runtime
}
});
Superadmin status is determined by the static configuration , not the graph
Each peer independently validates superadmin actions against its local config
Provides “root of trust” for the permission system
Superadmin Recognition:
function getSenderRole ( ethAddress ) {
// 1. Check static superadmin list FIRST
if ( this . config . superAdmins . includes ( ethAddress )) {
return 'superadmin' ;
}
// 2. Query distributed role from graph
const userNode = this . graph . get ( `user: ${ ethAddress } ` );
return userNode ?. value ?. role || 'guest' ;
}
This dual-source model ensures superadmins can operate immediately without waiting for network sync.
Access Control Lists (ACLs)
For node-level permissions beyond global RBAC, see the ACLs Module .
ACLs provide:
Per-node permissions (read, write, delete)
Ownership model (creator becomes owner)
Grant/revoke permissions to specific users
Integrates with RBAC (both checks must pass)
Best Practices
Use WebAuthn for Production
WebAuthn provides the best security and UX:
Passwordless authentication
Phishing-resistant
Hardware-backed keys (TPM, Secure Enclave)
Biometric unlock (Face ID, Touch ID, Windows Hello)
// Enable WebAuthn after registration
await sm . protectCurrentIdentityWithWebAuthn ();
Design Minimal Privilege Roles
Follow principle of least privilege: customRoles : {
editor : {
can : [ 'read' , 'write' , 'sync' ] // Can't delete
},
viewer : {
can : [ 'read' ] // Read-only
}
}
Monitor Permission Denials
db . on ( 'permission:denied' , ({ action , role , user }) => {
console . warn ( `Denied ${ action } for ${ role } ( ${ user } )` );
// Log to analytics
});
Use Role Expiration for Temporary Access
const expiresIn7Days = Date . now () + ( 7 * 24 * 60 * 60 * 1000 );
await sm . assignRole (
'0xtemporary...' ,
'editor' ,
expiresIn7Days
);
The system automatically downgrades to ‘guest’ after expiration.
Related Pages
WebAuthn Authentication Biometric and hardware-key authentication
Zero-Trust Model Security principles and trust model
Distributed Trust How trust works in a P2P network