Skip to content
Discord Get Started

Security and Auth

DB9 has multiple authentication layers: API-level bearer tokens for managing databases, database-level roles for SQL access, and short-lived connect tokens for secure credential handoff. This page explains each layer, how they interact, and where the current boundaries are.

LayerMechanismLifetimePurpose
Customer API tokenBearer token (128-char hex)365 days (configurable)Manage databases, users, branches, tokens
Anonymous tokenBearer token (auto-refreshed)90 days (renewable)Trial access before SSO claim
API key loginDB9_API_KEY env or db9 login --api-keySame as tokenCI/CD and headless automation
Connect tokenJWT (RS256-signed)5–15 minutesShort-lived database connection credential
Connect keydb9ck_-prefixed keyConfigurable (up to permanent)Long-lived programmatic database access
Database passwordSCRAM-SHA-256Permanent until resetDirect pgwire authentication

All database management goes through the customer API, protected by bearer tokens.

Every API request requires an Authorization: Bearer <token> header. Tokens are:

  • 128-character hex strings (64 random bytes)
  • Stored as SHA-256 hashes in the metadata database (one-way; cannot be recovered)
  • Created with an expiry (default: 365 days)
Terminal
# Login via SSO (browser-based Auth0 device flow)
db9 login
# Login with a pre-created API key (headless)
db9 login --api-key <TOKEN>
# Check current auth state
db9 status

Create additional tokens for automation, CI/CD, or team members:

Terminal
# Via CLI (uses the SDK under the hood)
db9 db connect-token <database>

Tokens can be listed and revoked through the API. The token value is only returned on creation — store it securely.

First-time users get an anonymous bearer token automatically when running db9 create without credentials. These auto-refresh using an anonymous secret stored locally. See Anonymous and Claimed Databases for the full lifecycle.

Every database is bootstrapped with an admin user that has superuser privileges:

  • SUPERUSER, LOGIN, CREATEDB, CREATEROLE
  • Password is randomly generated and stored encrypted (AES-256-GCM) in the backend

The admin password is used when you run db9 db connect <database> — the CLI retrieves it from the backend automatically.

Create regular (non-superuser) database users through the CLI or API:

Terminal
db9 db users create <database> <username> --password <password>

Regular users:

  • Can LOGIN to the database
  • Cannot create other users, alter the admin password, or perform superuser-only operations
  • Access is controlled by standard PostgreSQL GRANT statements

Usernames must be 1–63 characters, alphanumeric plus underscore, and cannot start with _db9_sys_ (reserved for internal system users).

CapabilitySuperuser (admin)Regular user
Run any SQLYesSubject to GRANTs
Use extensions (http, fs9, embedding, pg_cron)YesRestricted (most require superuser)
Create/drop usersYesNo
Create/drop tablesYesOnly if granted
View all cron jobsYesOwn jobs only
Cancel running cron jobsYesNo
Use cron.running_jobsYesNo

Connect tokens are short-lived JWTs for establishing database connections from external clients, ORMs, or tools that need temporary credentials.

Terminal
db9 db connect-token <database>
db9 db connect-token <database> --role <role>

Returns:

JSON
{
"host": "pg.db9.io",
"port": 5433,
"database": "postgres",
"user": "<tenant_id>.<role>",
"token": "<JWT>",
"expires_at": "2026-03-12T12:10:00Z"
}
  • Signing: RS256 (RSA private key), verifiable via public JWKS endpoint
  • TTL: 5–15 minutes (default 10 minutes), not configurable per-request
  • Scope: db:connect — limited to establishing a database connection
  • Role binding: Each token is bound to a specific database and role
  • JWKS verification: Public keys available at /.well-known/db9-connect-jwks.json for external token validation
  • Single use intent: Designed for handoff to a driver; create a new token for each connection
  • Passing credentials to an ORM or migration tool without exposing the admin password
  • Short-lived CI/CD database access
  • Programmatic connection from serverless functions

Connect keys are long-lived, scoped API keys for programmatic database access (especially the fs9 filesystem):

  • Prefixed with db9ck_ for easy identification
  • SHA-256 hashed in storage (like bearer tokens)
  • Support scopes: fs9:ro (read-only filesystem), fs9:rw (read-write filesystem)
  • Configurable expiry or permanent
  • Revocable at any time
CredentialStorage method
Customer bearer tokensSHA-256 hash (irreversible)
Connect keysSHA-256 hash (irreversible)
Database admin passwordsAES-256-GCM encrypted (requires DB9_CREDENTIAL_KEY)
Auth0 ID tokensValidated and discarded (not stored)

The CLI stores credentials in ~/.db9/credentials with owner-only permissions (0600). This file contains:

  • Bearer token
  • Customer ID
  • Anonymous ID and secret (if anonymous)

Running db9 logout clears this file.

DB9 uses the PostgreSQL wire protocol (pgwire v3) for SQL connections:

  • Authentication: Password-based (SCRAM-SHA-256 or plain, depending on configuration)
  • Multi-tenant isolation: Connection usernames are prefixed with the tenant ID (tenant_id.username), enforcing keyspace isolation at the wire level
  • Encryption: Wire-level TLS is not currently enforced between client and db9-server. Network-level encryption (VPN, private networking) is recommended for production.

All privilege-changing operations are logged to an audit trail:

  • Token creation and revocation
  • User creation and deletion
  • Connect key operations
  • Database lifecycle events

Audit logs are retained for 90 days by default.

These features are common in enterprise database platforms but are not available in DB9 today:

  • IP allowlisting — no built-in IP restrictions; use network-level controls
  • Wire-level TLS — pgwire connections are not encrypted; rely on network security
  • Multi-factor authentication — SSO (Auth0) is the only identity verification layer
  • Password complexity rules — no enforcement of length, character, or rotation policies
  • Automated credential rotation — revoke and re-create tokens manually
  • Row-level security (RLS) policies — standard PostgreSQL RLS is not yet supported
  • Column-level encryption — encrypt sensitive data at the application level