Choosing a store
A store saves wardn’s runtime data: assignments, custom roles and scope links. All the authorization logic lives in wardn itself, so every store behaves identically.
| Store | Use for | Package |
|---|---|---|
| SQL | PostgreSQL 13+, MySQL 8.0+, MariaDB 10.6+, SQLite 3.24+ | github.com/MogRex-Limited/wardn/store/sql (wardnsql) |
| pgx (v1.2) | PostgreSQL 13+, in applications built on pgx rather than database/sql |
github.com/MogRex-Limited/wardn/store/pgx (wardnpgx) |
| MongoDB | MongoDB 6.0+, standalone or replica set | github.com/MogRex-Limited/wardn/store/mongo (wardnmongo) |
| Memory | Tests, demos, and examples (lost on restart) | wardn.NewMemoryStore(), the default |
db, _ := sql.Open("pgx", dsn) // or "mysql", "sqlite"w := wardn.MustNew(wardn.Config{ File: "wardn.yaml", Store: wardnsql.MustNew(db), // dialect detected from the driver})Options: wardnsql.WithTablePrefix("authz_") (default wardn_) and wardnsql.WithDialect(wardnsql.Postgres) if detection can’t tell.
Size the connection pool for your concurrency, for example db.SetMaxIdleConns(32). The default keeps only 2 idle connections, which more than halved parallel check throughput on PostgreSQL (Performance).
pool, _ := pgxpool.New(ctx, dsn)w := wardn.MustNew(wardn.Config{ File: "wardn.yaml", Store: wardnpgx.MustNew(pool),})Option: wardnpgx.WithTablePrefix("authz_") (default wardn_).
Use it when your application already talks to PostgreSQL through pgx: wardn shares your pool, and store.WithTx(ctx, tx) takes your pgx.Tx, so access changes commit with your own writes (changes in your own transaction).
It creates exactly the same tables as the SQL store on PostgreSQL: names, columns, indexes, schema versions and migration lock. You can switch between the two, or run both against one database, with no data migration.
client, _ := mongo.Connect(options.Client().ApplyURI(uri))w := wardn.MustNew(wardn.Config{ File: "wardn.yaml", Store: wardnmongo.MustNew(client.Database("lending")),})Option: wardnmongo.WithCollectionPrefix("authz_"). No transactions are needed: every write touches one document.
Migrations
Section titled “Migrations”wardn.New creates and upgrades wardn’s tables (or indexes) automatically:
- Safe when many instances start at once: on SQL databases a lock serialises them; on MongoDB every step is safe to run concurrently.
- Safe to interrupt: every step can run twice, which matters on MySQL, which can’t undo schema changes.
- Never downgrades: a database already upgraded by a newer wardn is refused (
ErrSchemaTooNew), so an old deployment can’t misread it.
If your deploy pipeline runs migrations itself, set ManualMigrations: true and call store.Migrate(ctx) from the pipeline. store.SchemaVersion(ctx) reports the current version.
What every store guarantees
Section titled “What every store guarantees”Each store passes the same 25-check conformance suite against a real server on every change. The suite checks, among other things, that a store:
- matches IDs exactly.
O1never matcheso1. On MySQL and MariaDB, whose default text comparison ignores case, wardn stores IDs in binary columns. - never returns another user’s or another scope’s data.
- is safe against injection. All SQL values are parameters, and MongoDB values are never interpreted as query operators.
- keeps the race conditions that matter for security atomic. Two admins creating the same role name: one wins. Two admins editing the same role version: one wins.
- never widens time windows. Times are stored to the microsecond; starts round later and ends round earlier.
Questions about this page?
Ask below, point out something wrong or unclear, or suggest an improvement. Reading needs no account; to post, sign in with GitHub.