Open-source project
gin-contrib/authz avatar
gin-contrib/authz

gin-contrib/authz: Casbin authorization as a Gin middleware

gin-authz is an authorization middleware for Gin

829 stars59 forksGoMIT

At a glance

What is it?
Authz is a small Go middleware that puts a Casbin enforcer into a Gin router, so that each request is checked against a policy expressed as subject, object and action, and a denied request returns HTTP 403. The package itself is one file, and the policy model and its sample CSV live beside it in the repository.
Who is it for?
Authz suits a Gin service that has already decided to express access rules as Casbin policies and wants the check attached to the router rather than written into each handler, and it is a good fit for a team that wants a model file and a policy CSV rather than role checks scattered across handlers.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the middleware actually does

Authz is an authorization middleware for Gin, based on Casbin. That is the entire concept, and the value of it is that the policy decision comes from a policy file rather than from hand-written role checks in every handler.

The plugin is small by design. The repository holds a single implementation file, authz.go, alongside authz_test.go, the policy artefacts and the module files. There is no configuration layer, no rule DSL of its own and no separate runtime service. The repository contents say what it is: an adapter between two libraries.

The decision model is the Casbin one, and the README states it directly. Authorization determines a request based on subject, object and action, which means what subject can perform what action on what object. In this plugin the three terms have specific meanings. The subject is the logged-on user name. The object is the URL path for the web resource, with the example given as "dataset1/item1". The action is the HTTP method, like GET, POST, PUT or DELETE, or the high-level actions you defined yourself, like "read-file" or "write-blog".

The last part of that list is the interesting design option. A policy can key off the raw HTTP verb, which keeps the rules close to the transport, or off an action name you define, which keeps them close to what the domain means. The second is the one that survives a change of HTTP method.

Installing the package and wiring it in

The package is a standard Go module.

bash
go get github.com/gin-contrib/authz

The README's example is short enough to be the whole integration.

Go
package main

import (
  "net/http"

  "github.com/casbin/casbin/v2"
  "github.com/gin-contrib/authz"
  "github.com/gin-gonic/gin"
)

func main() {
  // load the casbin model and policy from files, database is also supported.
  e := casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")

  // define your router, and use the Casbin authz middleware.
  // the access that is denied by authz will return HTTP 403 error.
  router := gin.New()
  router.Use(authz.NewAuthorizer(e))
}

Three things are visible in that snippet. The enforcer is created from a model file and a policy file, and the comment notes that a database is also supported. The middleware is attached with router.Use, which means it applies to every route registered on that router. And the denied case is an HTTP 403.

The order of the two Use calls is the part that needs deciding. Because the middleware reads the logged-on user name, an authentication middleware that populates the request context has to run first, or the authorizer has nothing to evaluate. The README does not document that ordering requirement, so it is worth checking in your own integration.

The model and policy files shipped with the repository

The repository includes authz_model.conf and authz_policy.csv, which is a helpful detail for a new user because it means the shape of a policy is visible in the source tree rather than only in Casbin's own documentation.

The model file is the Casbin model, the part that says what a request tuple looks like and how it is matched. The policy file is the rules themselves, in CSV form, one rule per line. Casbin supports a database adapter as well, so the same model can be paired with a policy stored elsewhere, and the README notes that in the code comment where the enforcer is created.

This is where the separation of concerns in the design shows. Authz does not define the model, and it does not parse the policy. Casbin does both, and the README points at the Casbin documentation for how to write authorization policy and for the other details. What the middleware adds is the translation from an HTTP request into the subject, object and action triple, and the translation back into a 403.

That division has a practical consequence for maintenance. A team that wants richer matching, whether it is a role hierarchy, key matching, a priority model or a domain model, changes the model file and the policy, not the Go code. The Go code stays the same size.

Where gin-contrib/authz is the wrong tool

The first limitation is that the subject has to come from somewhere. The README describes the subject as the logged-on user name, which means the middleware expects an authentication layer that has already established who the caller is and put that into the request context. If you have no authentication yet, or if your identity model is a token with scopes rather than a user name, the wiring is not one line.

The second is the granularity. Because the object is the URL path, the policy is written against paths. A resource with its own ownership rule, where a user can edit their own record but not someone else's, does not map onto subject-object-action without either encoding the owner into the subject or extending the model. Casbin can express that with a custom function, but then the middleware is not enough on its own.

The third is the dependency weight for what it does. The go.mod requires casbin/v2 and gin, and the indirect list is long, including govaluate, the expression evaluation library Casbin uses for its matchers, plus the goccy and sonic JSON implementations and the quic-go stack that Gin 1.12 pulls in. A service that only needs a role check on three routes now carries an expression engine.

The fourth is the API surface. The README documents the middleware and the request tuple, and it does not document per-route overrides, a way to skip the check for a specific path, a way to pass a different action than the HTTP verb, or how the middleware behaves on a route that does not exist. Those behaviours are in the code rather than in the documentation, which is the normal state of a small adapter.

The fifth is the Go version requirement. The go.mod declares go 1.26.0, which is a recent toolchain floor, and a team on an older supported Go release cannot build this as it stands.

How it compares with writing role checks by hand and with OPA

The comparison with hand-written role checks is the one every team has to make. A hand-written check is a few lines in a handler, it needs no dependency, and it is instantly readable. What it does not do is give you a single place to answer the question of who can do what, and when the rules grow past a handful of roles they tend to diverge, one handler using a role table and another using a hardcoded comparison.

Authz moves those rules into a model file and a policy CSV. The trade is a dependency, a policy file to keep in step with the code, and the fact that a developer reading a handler no longer sees the rule in the handler. For a service with a handful of endpoints and simple roles, the hand-written check is honestly better. For a service where access rules are a product requirement that non-engineers also need to reason about, a policy file is better.

Open Policy Agent is the other comparison, and the difference in approach is the evaluation model. OPA evaluates a Rego policy document against an input document, which is a general policy language with its own runtime, its own bundles and its own distribution story. Casbin evaluates a request tuple against a model and a policy set, and the model is a small matching specification rather than a program. OPA is the right tool when the rules are genuinely arbitrary logic; Casbin is the right tool when the rules are permission grants, which is most access control.

The practical difference for a Gin service is deployment. OPA is a separate process or a sidecar that the application talks to, which means a network hop and a component to operate. Authz is a library call inside the process, so a policy change is a file change and a reload, with no extra infrastructure.

Licence, releases and the development workflow

The licence is MIT, and the README points at the LICENSE file for the full text. An MIT licence is about as permissive as open source gets, and it is a good fit for a middleware that most adopters will vendor into their own build rather than fork.

The project is not archived and the last push was on 2026-10-03, so it is being maintained. The release history is a steady sequence of patch releases, with v1.0.9 from 2026-09-21, v1.0.8 from 2026-09-05 and v1.0.7 from 2026-03-28. A version number still in the 1.0.x range after that many releases is a reasonable signal for a small adapter whose API is unlikely to move, though the README does not make a compatibility promise.

The development tooling is visible in the repository. There is a .golangci.yml for linting and a .goreleaser.yaml for release builds, and the Makefile defines the tasks. Linting and formatting both run through the Go tool mechanism with a separate tools module.

bash
$(GO) tool $(TOOLS_MOD) golangci-lint run

The separate go.tools.mod file is the pattern here: the linting tools are pinned in their own module so they do not pollute the dependency list of the library itself, and the Makefile invokes them through the tool directive with a modfile flag.

The test target runs the suite with coverage and writes a coverage profile.

bash
$(GO) test -v -cover -coverprofile=coverage.txt ./...

The CI badges in the README show what runs on every change: CodeQL for static analysis, the Go test workflow, a Trivy security scan and a codecov coverage report. That set is worth noting when you decide whether to depend on the package, since a middleware in front of every request deserves that scrutiny.

Editorial conclusion

Authz suits a Gin service that has already decided to express access rules as Casbin policies and wants the check attached to the router rather than written into each handler, and it is a good fit for a team that wants a model file and a policy CSV rather than role checks scattered across handlers. It is the wrong tool for a service that needs per-resource ownership rules the model does not express, and the wrong choice for a team that wants no policy engine dependency at all, since the enforcer and the govaluate expression library come with it. Before wiring it in, decide where the subject comes from, because the middleware expects a logged-on user name that your authentication layer has to place in the request context.

Frequently asked questions

How do I install gin-contrib/authz?

Run `go get github.com/gin-contrib/authz`. The package is a Go module whose go.mod declares module path github.com/gin-contrib/authz and requires Go 1.26.0.

What does the authz middleware do when access is denied?

The README states that access denied by authz returns an HTTP 403 error. The middleware is attached to the router with router.Use(authz.NewAuthorizer(e)), so it applies to every route on that router.

What do subject, object and action mean in gin-contrib/authz?

The subject is the logged-on user name, the object is the URL path for the web resource such as dataset1/item1, and the action is the HTTP method like GET, POST, PUT or DELETE, or a high-level action you defined yourself such as read-file.

Where are the Casbin model and policy files for gin-contrib/authz?

The repository includes authz_model.conf and authz_policy.csv, and the README example loads them with casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"). The code comment notes that a database is also supported as the policy source.

What licence is gin-contrib/authz released under?

MIT, with the full licence text in the LICENSE file at the root of the repository.

How is gin-contrib/authz tested and linted?

The Makefile runs golangci-lint through the Go tool mechanism with a separate go.tools.mod file, and the test target runs the suite with coverage, writing a coverage profile. CI runs CodeQL, the Go tests, a Trivy security scan and codecov.

Official sources

  1. gin-contrib/authz on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gin-contrib-authz.svg)](https://hysenlabs.com/projects/gin-contrib-authz)

Was this useful?