Your model, not ours
wardn knows nothing about banks, schools or SaaS. Each product declares its own permissions, roles and scope tree: flat, one level, or as deep as it needs.
Describe your product in one file, start wardn in main, and put Require on your routes. Tables are created for you, typos stop the app at startup, and every denial is explained.
scopes: organisation: {} branch: { parent: organisation }
permissions: customer:view: View customers loan:create: Create loan applications loan:approve: Approve loans
roles: org_admin: assignable_at: [organisation] allow: ["*"] teller: assignable_at: [branch] allow: [customer:view, loan:create]db, _ := sql.Open("pgx", os.Getenv("DATABASE_URL"))
w := wardn.MustNew(wardn.Config{ File: "wardn.yaml", Store: wardnsql.MustNew(db), // creates its tables on startup})r.Route("/branches/{branchID}", func(r chi.Router) { r.Use(w.ScopeFrom("branch", wardn.PathValue("branchID"))) r.With(w.Require("loan:create")).Post("/loans", createLoan) r.With(w.Require("loan:approve")).Post("/loans/{id}/approve", approveLoan)})Your model, not ours
wardn knows nothing about banks, schools or SaaS. Each product declares its own permissions, roles and scope tree: flat, one level, or as deep as it needs.
Ten minutes to a protected route
One YAML file, one constructor, one middleware. No policy language, no extra server. Mistakes fail at startup with a “did you mean …?”.
Secure by default
Default deny. Deny always wins. Any error means “no”. Tenants are isolated. Error responses reveal nothing. None of this can be switched off.
Custom roles, no escalation
Let admins create roles at runtime. The escalation guard ensures nobody can grant, edit or remove a role with more power than they hold.
Works with your database
PostgreSQL, MySQL, MariaDB, SQLite and MongoDB, with automatic migrations. Optional Redis caching across instances that never serves stale access.
Built to be audited
Every check explains itself. Every change is audited before it happens. A threat model, a security review and a test for every threat ship with the code.
Each idea builds on the one before. Learn these four and you know wardn.
An action your code checks.
loan:approveA named set of permissions.
teller: [customer:view, loan:create]Where a role applies. Roles flow down the tree.
organisation › region › branchGives a user a role in a scope, optionally until a set time.
bayo → teller @ branch:lagosPut together, in a bank:
organisation:acme ada → org_admin (everything in Acme) └── region:south └── branch:lagos bayo → teller (this branch only) tolu → loan_officer (until Friday)A flaw in an authorization library is a flaw in every product that uses it. So wardn is tested the way attackers think.
| wardn | Casbin | OpenFGA / SpiceDB | Home-grown | |
|---|---|---|---|---|
| Built for | Roles and tenancy inside a Go product | General policy models, in many languages | Sharing individual objects across millions of them (Zanzibar-style) | A product’s first few checks |
| Runs | Inside your app, on your database | Inside your app | As a separate service | Inside your app |
| Your team learns | One YAML file | Casbin’s model language | A modelling language and relationship tuples | Nothing new, at first |
| Tenancy and hierarchy | Built in | Domains built in; scope trees are yours to build | Built in, as relationships | Yours to build |
| Admin-created roles that can’t escalate | Built in | Yours to build | Yours to build | Rarely done |
| Time-limited access | Built in | Yours to build | Supported | Rarely done |
| Audit of every change | Built in, and can block a change | Yours to build | Change history API | Rarely done |
Different tools for different jobs. wardn is built for roles and tenancy inside a Go product: no extra service, no new language, and the safety rules built in. OpenFGA and SpiceDB are built for sharing individual objects between people and groups at very large scale. They work well together: many products use wardn for who runs what in the organisation, and a relationship service for who can see which document.
Ask other developers who use wardn, suggest a feature, or raise a concern. Every answer stays searchable for the next person.