Skip to content

Role-Based Access Control (RBAC)

Fine-grained access control with JWT authentication.

Overview

NornicDB implements role-based access control (RBAC) to meet compliance requirements:

  • JWT Authentication - Stateless token-based auth
  • 4 Built-in Roles - Admin, Editor, Viewer, None
  • Permission System - Read, Write, Admin permissions
  • Account Security - Lockout, password policies

Roles and Permissions

Built-in Roles

Role Read Write Admin Description
admin Full access, user management
editor Read and write data
viewer Read-only access
none No access (disabled)

Permission Mapping

// Permissions
auth.PermRead   // Read nodes, edges, run queries
auth.PermWrite  // Create, update, delete data
auth.PermAdmin  // User management, configuration

Configuration

Server Configuration

# nornicdb.yaml
auth:
  enabled: true

  # JWT settings
  jwt_secret: "${NORNICDB_JWT_SECRET}"  # Min 32 chars
  jwt_expiry: 24h

  # Password policy
  min_password_length: 12
  require_uppercase: true
  require_number: true
  require_special: true

  # Security
  max_failed_attempts: 5
  lockout_duration: 15m

Environment Variables

# Required: JWT signing secret (min 32 characters)
export NORNICDB_JWT_SECRET="your-super-secret-jwt-key-min-32-chars"

# Optional: Disable auth for development
export NORNICDB_NO_AUTH=true

User Management

User Storage and Persistence

NornicDB stores all user accounts in the system database for persistence and security:

  • Persistent Storage: Users are stored as nodes in the system database with labels ["_User", "_System"]
  • Automatic Loading: All users are automatically loaded from the system database on server startup
  • Backup Integration: User accounts are included in database backups automatically
  • GDPR Compliance: User data can be exported and deleted via GDPR endpoints
  • Security: Internal database IDs are never exposed in API responses

Storage Details: - Users are stored as graph nodes (not separate tables) - Node ID format: user:{username} (e.g., user:admin) - All user operations (create, update, delete) are persisted immediately - In-memory cache provides fast lookups while maintaining persistence

Create Users

# Via Web UI (Admin Panel)
# Navigate to /security/admin as an admin user

# Via API
curl -X POST http://localhost:7474/auth/users \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "alice",
    "password": "SecurePass123!",
    "roles": ["viewer"]
  }'

Response:

{
  "username": "alice",
  "email": "alice@localhost",
  "roles": ["viewer"],
  "created_at": "2024-12-01T10:30:00Z",
  "disabled": false
}

Note: Internal database IDs are never included in responses for security reasons.

Manage Users

# List all users (admin only)
curl -X GET http://localhost:7474/auth/users \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# Get specific user
curl -X GET http://localhost:7474/auth/users/alice \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# Update user roles
curl -X PUT http://localhost:7474/auth/users/alice \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"roles": ["editor"]}'

# Disable user
curl -X PUT http://localhost:7474/auth/users/alice \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"disabled": true}'

# Delete user
curl -X DELETE http://localhost:7474/auth/users/alice \
  -H "Authorization: Bearer $ADMIN_TOKEN"

User Profile Management

Users can manage their own profiles via the Security page (/security):

Change Password:

curl -X POST http://localhost:7474/auth/password \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "old_password": "OldPass123!",
    "new_password": "NewSecurePass456!"
  }'

Update Profile:

curl -X PUT http://localhost:7474/auth/profile \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@example.com",
    "metadata": {
      "department": "Engineering",
      "team": "Backend"
    }
  }'

Authentication

Login (Get Token)

# OAuth 2.0 password grant
curl -X POST http://localhost:7474/auth/token \
  -d "grant_type=password&username=alice&password=SecurePass123!"

# Response
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 86400
}

Using Tokens

# Authorization header
curl http://localhost:7474/db/nornicdb/tx/commit \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

# Or API key header
curl http://localhost:7474/db/nornicdb/tx/commit \
  -H "X-API-Key: your-api-key"

API Key Authentication

For service-to-service communication:

# Create API key
nornicdb apikey create --name "backend-service" --role editor

# Use API key
curl http://localhost:7474/nornicdb/search \
  -H "X-API-Key: ndb_sk_abc123..."

Endpoint Protection

Protected Endpoints

Endpoint Required Permission
GET /health None (public)
GET /status read
GET /metrics read
POST /db/nornicdb/tx/commit read or write
POST /nornicdb/search read
DELETE /nornicdb/gdpr/* admin
POST /auth/users admin

Code Example

// Check permissions in handler
func (s *Server) handleProtectedEndpoint(w http.ResponseWriter, r *http.Request) {
    claims := r.Context().Value(claimsKey).(*auth.Claims)

    if !claims.HasPermission(auth.PermWrite) {
        http.Error(w, "Forbidden", http.StatusForbidden)
        return
    }

    // Handle request...
}

Security Features

Account Lockout

After 5 failed login attempts, accounts are locked for 15 minutes:

// Attempt login
token, user, err := auth.Authenticate("alice", "wrongpass", ip, agent)
// After 5 failures: ErrAccountLocked

// Check lockout status
user.IsLocked()     // true
user.LockedUntil    // time.Time

Password Hashing

Passwords are hashed using bcrypt with automatic salt generation:

  • Algorithm: bcrypt with configurable cost factor (default: 10)
  • Salt: Automatically generated and embedded in the hash (no separate salt storage needed)
  • Storage: Password hashes are stored in the system database, never in plain text
  • Security: Internal database IDs and password hashes are never exposed in API responses
// Passwords are never stored in plain text
// Bcrypt automatically salts passwords
// Uses bcrypt.DefaultCost (10) - configurable via BcryptCost
hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
// Salt is embedded in the hash - no separate storage needed

Configuration:

auth:
  bcrypt_cost: 10  # Higher = more secure but slower (4-31, default: 10)
  min_password_length: 8  # Minimum password length

Session Management

// Logout invalidates token (adds to blacklist)
auth.Logout(token)

// Validate token checks blacklist
claims, err := auth.ValidateToken(token)
// Returns ErrTokenRevoked if blacklisted

Compliance Mapping

Requirement NornicDB Feature
GDPR Art.32 Access controls, authentication
HIPAA §164.312(a)(1) Unique user identification
HIPAA §164.312(d) Person or entity authentication
FISMA AC-2 Account management
SOC2 CC6.1 Logical access controls

Audit Integration

All authentication events are logged:

{
  "timestamp": "2024-12-01T10:30:00Z",
  "event_type": "LOGIN",
  "user_id": "usr_abc123",
  "username": "alice",
  "ip_address": "192.168.1.100",
  "user_agent": "Mozilla/5.0...",
  "success": true
}

See Audit Logging for details.

See Also