Keysmith

PostgreSQL Store

Production PostgreSQL backend using pgx/v5.

The PostgreSQL store provides a full store.Store implementation using pgx/v5 connection pools. It includes embedded SQL migrations and is the recommended backend for production.

Setup

import "github.com/xraph/keysmith/store/postgres"

pgStore, err := postgres.New(ctx, "postgres://user:pass@localhost:5432/mydb")
if err != nil {
    log.Fatal(err)
}
defer pgStore.Close()

Migrations

The store embeds SQL migrations using go:embed. Run them on startup:

if err := pgStore.Migrate(ctx); err != nil {
    log.Fatal(err)
}

This creates five tables:

TableDescription
keysmith_keysAPI keys with hash, state, and metadata
keysmith_policiesPolicy definitions
keysmith_scopesScope definitions
keysmith_key_scopesKey-scope junction table
keysmith_usagePer-request usage records
keysmith_usage_aggAggregated usage (daily/monthly)
keysmith_rotationsRotation history records

Migrations are idempotent and safe to run on every startup.

Connection pooling

The store uses pgx's built-in connection pool. Configure pool settings via the connection string or pgx options:

// Via connection string
pgStore, err := postgres.New(ctx,
    "postgres://user:pass@localhost:5432/mydb?pool_max_conns=20",
)

Health checks

if err := pgStore.Ping(ctx); err != nil {
    log.Fatal("database unreachable:", err)
}

Usage with the engine

eng, err := keysmith.NewEngine(keysmith.WithStore(pgStore))

Schema overview

keysmith_keys

CREATE TABLE keysmith_keys (
    id          TEXT PRIMARY KEY,
    name        TEXT NOT NULL,
    hash        TEXT NOT NULL UNIQUE,
    prefix      TEXT NOT NULL,
    environment TEXT NOT NULL,
    state       TEXT NOT NULL DEFAULT 'active',
    app_id      TEXT NOT NULL,
    tenant_id   TEXT NOT NULL,
    policy_id   TEXT,
    expires_at  TIMESTAMPTZ,
    last_used_at TIMESTAMPTZ,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_keys_hash ON keysmith_keys (hash);
CREATE INDEX idx_keys_tenant ON keysmith_keys (app_id, tenant_id);
CREATE INDEX idx_keys_state ON keysmith_keys (state);

On this page