# Apache Casbin: an authorization library for Go that keeps policy out of your code

> Casbin turns access rules into a model file plus a policy store, then enforces them at runtime. This review covers what the Go library actually does, how to install it, and where it stops being the right tool.

**apache/casbin** — Apache Casbin: an authorization library that supports access control models like ACL, RBAC, ABAC.

- Repository: https://github.com/apache/casbin
- Website: https://casbin.apache.org/
- Stars: 20,409 · Forks: 1,758
- Language: Go
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/apache-casbin

## What Apache Casbin decides, and what it leaves to you

Casbin is an authorization library, not an identity provider. It answers one question: given a subject, an object and an action, is this allowed? Everything upstream of that question, meaning who the user is, how they logged in and what token they carry, is outside its scope. The README lists the access control models it supports: ACL, ACL with superuser, ACL without users, ACL without resources, RBAC, RBAC with resource roles, RBAC with domains or tenants, ABAC, and RESTful path matching such as /res/* and /res/:id.

The audience is Go teams that have outgrown scattered if statements. A service that hardcodes permissions ends up redeploying whenever a role changes. Casbin moves that decision into two artifacts: a model file that describes the shape of the rules, and a policy store that holds the actual assignments. The library itself is small; go.mod shows three direct dependencies, doublestar for glob matching, govaluate for expression evaluation, and google/uuid.

## How the model file, policy store and enforcer fit together

The mechanism is a request-to-policy match. A model file declares request parameters, policy parameters, and one or more matchers. The policy store supplies rows that the matcher consumes. The enforcer loads both and evaluates each incoming request against the matcher.

The repository ships a set of example configurations under examples/, including basic_model.conf, basic_policy.csv, abac_model.conf, abac_rule_model.conf, glob_model.conf, ipmatch_model.conf, biba_model.conf and blp_model.conf. The presence of Biba and BLP models alongside the usual RBAC files shows how far the model-driven approach stretches: those are classic mandatory access control formulations expressed as matchers rather than as library features. That is the real design bet. Casbin does not implement RBAC as a special case with dedicated code paths; it implements a matcher engine, and RBAC is a pattern you write in the model.

The consequence cuts both ways. You gain the ability to express a policy shape the library author never anticipated. You also take on the job of getting that model right, and a matcher that is subtly wrong fails open or closed without a compile error to warn you.

## Installing Apache Casbin and running a first enforcement check

The Go module path in go.mod is github.com/casbin/casbin/v3, so that is what you import. The README's installation section points at the standard Go tooling; the module declares go 1.13 as its language version. The repository's own build target is the shortest way to confirm a checkout compiles and passes its tests:

```bash
go test -race -v ./...
```

That command comes from the Makefile's test target. With the example files from the repository present in a local examples/ directory, the README's get-started flow creates an enforcer with NewEnforcer, passing a model file and a policy file, then calls Enforce with the subject, object and action. The names used in the README's own examples are alice, data1, read and write, and the example files that pair with them are examples/basic_model.conf and examples/basic_policy.csv.

NewEnforcer returns an error, and the get-started flow treats that error as something to handle rather than ignore. Each Enforce call returns a boolean against the loaded policy. What you should see is a true for the read that the example policy grants and a false for the write it does not. If both come back the same, the model and policy files are not the pair you think they are.

The repository also exposes a management API for changing policy at runtime, which is what makes the separation useful in production rather than only at startup. The online editor at the project's site, linked from the README, is the fastest way to check a model before wiring it into a service.

## Where Casbin is the wrong tool

Casbin does not authenticate anyone. It has no login flow, no password storage, no token issuance and no user directory. If your problem is "we need single sign-on across five applications", Casbin does not solve it, and the topics list on the repository, which mentions oauth, oidc, saml and sso, describes the surrounding ecosystem rather than features of this library.

Policy consistency across multiple nodes is a second sharp edge. The README has a section titled policy consistency between multiple nodes, which is itself a signal that this is a problem you must think about. An enforcer holds policy in memory. Two instances with different policy views will make different decisions for the same request. The repository ships enforcer_cached.go, enforcer_cached_synced.go, enforcer_synced.go and enforcer_distributed.go, so there are building blocks, but choosing among them and keeping them coherent is your design work, not a setting you flip.

A third limit is scope. The README notes that ACL without resources targets permission types like write-article rather than individual articles. If your requirements are genuinely per-row, for example "this user may edit this specific document because they are its owner", you are in ABAC territory and the matcher will need access to resource attributes. That works, but it means the enforcer call has to receive an object, not just a resource string, and the calling code gets more involved.

## Casbin against OPA, Keycloak and Casdoor

The comparison people search for most is Casbin versus OPA. They are both policy engines, but they sit at different layers. Casbin is a library you link into your Go process; the decision happens in the same binary as your service, with no network hop. OPA is typically deployed as a separate decision service reached over HTTP, with policy written in Rego. That difference decides a lot: in-process enforcement avoids a round trip and a new failure mode, while a sidecar or daemon gives you one policy authority shared across services written in different languages.

Keycloak is a different category again. It is an identity and access management server, handling users, credentials and tokens. Casbin makes decisions about users that something else has already identified. They are complementary more than competing.

Casdoor appears in the same search space because it is a related project in the Casbin ecosystem, oriented toward a full identity and authorization platform rather than a library. If you want a product with a UI and user management, the library is the wrong shape. If you want a decision function inside your own service, the platform is too much machinery.

One practical point in Casbin's favor for polyglot shops: the README lists implementations for Go, Java, Node.js, PHP, Python, .NET, C++ and Rust, each marked as production-ready, and the model and policy files are meant to be portable across them. A team with a Go backend and a Python data job can share the same policy semantics.

## Maintenance, licensing and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-11. The most recent release listed is v3.11.0 from 2026-08-20, preceded by snapshot builds in June 2026. That is a short gap between the latest release and the latest commit, which is a reasonable sign that the release line tracks the branch.

Upgrade cost is mostly about the model, not the API. Casbin's public surface is small: construct an enforcer, call Enforce, use the management API to change policy. The churn risk lives in the expression evaluator, which comes from the govaluate dependency, and in the matcher functions the model calls. A model file that uses an expression syntax the newer evaluator rejects will fail at load time, and that failure appears when NewEnforcer runs, not at compile time. Pinning the module version and having a test that loads your production model and policy files is the cheapest insurance available here.

Licensing is Apache-2.0, the same licence as the rest of the Apache project, with the standard header reproduced at the top of the README and the Makefile. The README states the software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. That is a permissive licence with an explicit patent grant, and it imposes no copyleft obligation on your application. It is not legal advice, and if you redistribute the library or embed it in a product, the NOTICE file in the repository is the thing to read.

The Makefile has three targets: test runs go test -race -v ./..., benchmark runs go test -bench=., and lint runs golangci-lint run --verbose. If you fork or vendor the library, that is the full local verification loop.

## Conclusion

Adopt Apache Casbin if your authorization rules change often enough that recompiling them into Go code has become painful, and if you are willing to keep a model file and a policy store in sync with your application. Skip it if you need a full identity platform, since Casbin only makes the allow or deny decision and leaves login, tokens and user records to something else. Before committing, verify how the enforcer is wired into your request path, which adapter you will use for policy persistence, and whether the model you have in mind, especially RBAC with domains or an ABAC expression, actually loads with the example files in the repository.

## FAQ

### What is Apache Casbin used for?

It is an access control library for enforcing authorization decisions in Go projects, supporting models such as ACL, RBAC and ABAC. It answers whether a subject may perform an action on an object, and leaves authentication to other components.

### Is Apache Casbin free and open source?

Yes. The repository is licensed under Apache-2.0, and the README carries the standard Apache licence header.

### How do I use Casbin in a Go project?

Import github.com/casbin/casbin/v3, create an enforcer with NewEnforcer pointing at a model file and a policy file, then call Enforce with the subject, object and action. The repository's examples/ directory contains model and policy pairs such as basic_model.conf and basic_policy.csv.

### How does Casbin compare with OPA?

Casbin is a library linked into your process, so the decision happens locally with no network hop. OPA is generally run as a separate decision service with policies written in Rego, which suits sharing one policy authority across services in different languages.

### How does Casbin relate to Keycloak?

They operate at different layers. Keycloak is an identity and access management server that handles users, credentials and tokens, while Casbin only makes the authorization decision for a subject that has already been identified.

## Sources

- [apache/casbin on GitHub](https://github.com/apache/casbin)
- [License: Apache-2.0](https://github.com/apache/casbin/blob/master/LICENSE)
- [Project website](https://casbin.apache.org/)
- [README](https://github.com/apache/casbin/blob/master/README.md)
- [Releases](https://github.com/apache/casbin/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apache-casbin
