Skip to content

Authentication and Authorization

havn includes built-in authentication with role-based access control (RBAC). When enabled, users must log in to access the web UI and API. Roles control what actions each user can perform.

Enabling Authentication

Start the server with the --auth flag:

havn serve --auth

Without --auth, all endpoints are accessible without authentication (suitable for local development).

Initial Setup

On first launch with --auth, no users exist. The web UI presents a setup screen to create the first admin user. Alternatively, use the API:

curl -X POST http://localhost:3000/api/auth/setup \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "your-password", "role": "admin"}'

This creates the first admin user and returns a token:

{
  "token": "abc123...",
  "username": "admin",
  "role": "admin"
}

The setup endpoint only works when no users exist. After the first user is created, additional users must be created by an admin.

Roles and Permissions

havn defines three roles with cumulative permissions:

Role Permissions Description
viewer read Browse tables, view DAG, run queries (read-only)
editor read, write, execute All viewer permissions plus run pipelines, edit files, manage data
admin read, write, execute, manage_users, manage_secrets Full access including user management and secrets

Permission Details

  • read -- View tables, run SELECT queries, browse files, view DAG, view history
  • write -- Edit files, save models, create versions, manage masking policies
  • execute -- Run pipelines, execute scripts, trigger transforms, import data
  • manage_users -- Create, update, delete users
  • manage_secrets -- View, set, delete secrets in .env

Authentication Flow

Login

curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "your-password"}'

Returns:

{
  "token": "abc123...",
  "username": "admin"
}

Using Tokens

Include the token in the Authorization header for all subsequent requests:

curl http://localhost:3000/api/tables \
  -H "Authorization: Bearer abc123..."

Token Lifetime

Tokens expire after 30 days by default. After expiration, the user must log in again to get a new token.

Check Auth Status

curl http://localhost:3000/api/auth/status

Returns whether auth is enabled and whether initial setup is needed:

{
  "auth_enabled": true,
  "needs_setup": false
}

Get Current User

curl http://localhost:3000/api/auth/me \
  -H "Authorization: Bearer abc123..."

Returns:

{
  "username": "admin",
  "role": "admin",
  "display_name": "Admin User"
}

User Management

All user management operations require the admin role.

List Users

curl http://localhost:3000/api/users \
  -H "Authorization: Bearer <admin-token>"

Returns:

[
  {
    "username": "admin",
    "role": "admin",
    "display_name": "Admin User",
    "created_at": "2025-01-15 06:00:00",
    "last_login": "2025-01-15 12:30:00"
  }
]

Create User

curl -X POST http://localhost:3000/api/users \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "analyst",
    "password": "secure-password",
    "role": "viewer",
    "display_name": "Data Analyst"
  }'

Username constraints: alphanumeric, underscores, dots, and hyphens. Password minimum: 4 characters.

Update User

curl -X PUT http://localhost:3000/api/users/analyst \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{"role": "editor", "display_name": "Senior Analyst"}'

You can update role, password, and display_name independently.

Delete User

curl -X DELETE http://localhost:3000/api/users/analyst \
  -H "Authorization: Bearer <admin-token>"

Deleting a user also revokes all their active tokens.

Password Security

Passwords are stored using PBKDF2 with SHA-256 and 100,000 iterations:

  • A 32-byte random salt is generated per user
  • The password is hashed with PBKDF2(SHA256, password, salt, 100000)
  • Only the hash and salt are stored -- passwords are never stored in plaintext

Rate Limiting

The login endpoint is rate-limited to prevent brute-force attacks. Each client IP is limited in its login attempt frequency.

Secrets Management

Admin users can manage secrets (.env variables) through the API:

List Secrets

curl http://localhost:3000/api/secrets \
  -H "Authorization: Bearer <admin-token>"

Returns keys with masked values (never exposes actual secret values in the API response).

Set a Secret

curl -X POST http://localhost:3000/api/secrets \
  -H "Authorization: Bearer <admin-token>" \
  -H "Content-Type: application/json" \
  -d '{"key": "DB_PASSWORD", "value": "new-password"}'

Delete a Secret

curl -X DELETE http://localhost:3000/api/secrets/DB_PASSWORD \
  -H "Authorization: Bearer <admin-token>"

Data Storage

Auth data is stored in the DuckDB database under _havn:

  • _havn.users -- User accounts (username, password hash, salt, role)
  • _havn.tokens -- Active authentication tokens with expiration