Skip to content

Introduction

wardn is simple, opinionated authorization for Go. It answers one question for any product: is this user allowed to do this, here?

Every product needs roles and permissions, and every product is different. A bank has organisations, regions and branches. A SaaS product has workspaces. A school has schools and classes. wardn doesn’t pick a model for you. Each product describes its own world in one file, and wardn does everything else.

  • Checks access on every request, with a reason for every decision.
  • Protects HTTP routes with one line of middleware, for net/http and chi.
  • Models tenancy and hierarchy, so an organisation admin automatically acts in every branch of that organisation and nowhere else.
  • Stores who has which role in your existing PostgreSQL, MySQL, MariaDB, SQLite or MongoDB database, and creates its tables for you.
  • Lets administrators create custom roles at runtime, with an escalation guard: nobody can grant more power than they hold.
  • Grants access for a limited time, such as a temporary approver until Friday, with no cleanup job required.
  • Records every change before it happens, for your audit trail.

wardn is deliberately focused on one job, and works alongside the tools that do the others:

  • Signing people in stays with your login, JWT or session code. It says who the user is; wardn decides what they may do.
  • Business conditions such as “approve loans under ₦5M” go in your code, right after wardn says yes. An optional module for common conditions is planned.
  • Sharing individual objects between people and groups across millions of objects, such as “editor of a folder can edit every document inside it”, is the job of a relationship service such as OpenFGA or SpiceDB. Many products use one alongside wardn.
  • There is no server to run. wardn is a library inside your application, on the database you already have.

wardn makes a small number of firm choices, so every product behaves the same way and developers learn it once:

Choice Why
Default deny. No role, no access. Forgotten grants fail safe.
Deny always wins over any allow. Restrictions can’t be overridden by accident.
Any error means “no”. A database outage never opens the doors.
Roles flow down the scope tree, never up or sideways. Tenants stay isolated.
Permissions are code; roles are data. Admins can combine permissions, but never invent ones your code doesn’t check.
Typos stop the app at startup. Mistakes surface in development, not in production.

None of these can be turned off. That’s the point.

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.