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.
Auth Model at a Glance
Section titled “Auth Model at a Glance”| Layer | Mechanism | Lifetime | Purpose |
|---|---|---|---|
| Customer API token | Bearer token (128-char hex) | 365 days (configurable) | Manage databases, users, branches, tokens |
| Anonymous token | Bearer token (auto-refreshed) | 90 days (renewable) | Trial access before SSO claim |
| API key login | DB9_API_KEY env or db9 login --api-key | Same as token | CI/CD and headless automation |
| Connect token | JWT (RS256-signed) | 5–15 minutes | Short-lived database connection credential |
| Connect key | db9ck_-prefixed key | Configurable (up to permanent) | Long-lived programmatic database access |
| Database password | SCRAM-SHA-256 | Permanent until reset | Direct pgwire authentication |
API Authentication
Section titled “API Authentication”All database management goes through the customer API, protected by bearer tokens.
Bearer tokens
Section titled “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)
# 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 statedb9 statusNamed API tokens
Section titled “Named API tokens”Create additional tokens for automation, CI/CD, or team members:
# 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.
Anonymous tokens
Section titled “Anonymous tokens”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.
Database Authentication
Section titled “Database Authentication”Admin user
Section titled “Admin user”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.
Additional users
Section titled “Additional users”Create regular (non-superuser) database users through the CLI or API:
db9 db users create <database> <username> --password <password>Regular users:
- Can
LOGINto the database - Cannot create other users, alter the admin password, or perform superuser-only operations
- Access is controlled by standard PostgreSQL
GRANTstatements
Usernames must be 1–63 characters, alphanumeric plus underscore, and cannot start with _db9_sys_ (reserved for internal system users).
Superuser vs. regular user
Section titled “Superuser vs. regular user”| Capability | Superuser (admin) | Regular user |
|---|---|---|
| Run any SQL | Yes | Subject to GRANTs |
| Use extensions (http, fs9, embedding, pg_cron) | Yes | Restricted (most require superuser) |
| Create/drop users | Yes | No |
| Create/drop tables | Yes | Only if granted |
| View all cron jobs | Yes | Own jobs only |
| Cancel running cron jobs | Yes | No |
Use cron.running_jobs | Yes | No |
Connect Tokens
Section titled “Connect Tokens”Connect tokens are short-lived JWTs for establishing database connections from external clients, ORMs, or tools that need temporary credentials.
db9 db connect-token <database>db9 db connect-token <database> --role <role>Returns:
{ "host": "pg.db9.io", "port": 5433, "database": "postgres", "user": "<tenant_id>.<role>", "token": "<JWT>", "expires_at": "2026-03-12T12:10:00Z"}Properties
Section titled “Properties”- 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.jsonfor external token validation - Single use intent: Designed for handoff to a driver; create a new token for each connection
When to use connect tokens
Section titled “When to use connect tokens”- 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
Section titled “Connect Keys”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
Credential Storage
Section titled “Credential Storage”Server side
Section titled “Server side”| Credential | Storage method |
|---|---|
| Customer bearer tokens | SHA-256 hash (irreversible) |
| Connect keys | SHA-256 hash (irreversible) |
| Database admin passwords | AES-256-GCM encrypted (requires DB9_CREDENTIAL_KEY) |
| Auth0 ID tokens | Validated and discarded (not stored) |
Client side
Section titled “Client side”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.
Wire Protocol Security
Section titled “Wire Protocol Security”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.
Audit Trail
Section titled “Audit Trail”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.
What Is Not Currently Supported
Section titled “What Is Not Currently Supported”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
Next Pages
Section titled “Next Pages”- Anonymous and Claimed Databases — trial accounts, claiming, and upgrade flow
- Production Checklist — verify auth and security before going live
- CLI Reference —
db9 login,db9 db connect-token,db9 db users - TypeScript SDK —
connectToken()and programmatic auth - SQL Reference: Auth and Roles —
CREATE ROLE,GRANT, and role management in SQL