go-security is net/http middleware: every leg of the chain is a func(http.Handler) http.Handler, and securityhttp.NewHandler returns a single http.Handler. Any Go router that implements http.Handler — which is nearly all of them — therefore integrates in one line, with no adapter and no framework-specific package to install.

Support matrix

The security chain sits outside the framework’s router, so it runs before routing happens. That is what you want: security headers, CORS, rate limiting, session lookup, CSRF, and default-deny authorization all apply to every request, including the ones your router has no route for. It is also the only way to get the login endpoint securityhttp.WithLogin mounts.
Then serve it like any handler:
Route patterns in authz.Match are matched against the raw request path, before your framework parses path parameters. Write them as paths (/admin/**, /api/v1/**), not as framework route templates (/users/:id, /users/{id}) — those template strings never appear in a request URL.

Pattern 2 — middleware inside the framework

Chain-level authz.Match rules cover most needs, but sometimes you want the guard next to the route, in the framework’s own idiom (r.Group, e.Group, r.Route). Every guard in web/middlewareRequireAuthenticated, RequireRole, RequireAuthority, BasicAuth — is a plain net/http middleware, so it composes with whatever adapter the framework offers. Use both layers together: keep the chain outside (headers, session, CSRF, default-deny) and add per-route role checks inside.

chi and gorilla/mux

Both are net/http-native, so the middleware is used as-is:

Echo

Echo ships the adapter:
echo.WrapMiddleware puts the request the middleware passed down back on the Echo context, so handlers downstream see the authentication.

Gin

Gin has gin.WrapH for handlers but no wrapper for middleware, so write the adapter once:
Both details matter. Skip c.Request = r and any context the middleware added is lost downstream. Skip c.Abort() and a denied request still reaches your handler, which then writes a 200 body after the 401 — a fail-open bug.

Role hierarchy in per-route checks

middleware.RequireRole / RequireAuthority are literal authority checks — they compare what the principal holds against what you asked for, and consult no role hierarchy. Under ADMIN > STAFF > USER, an ADMIN caller is denied by middleware.RequireRole("STAFF"). Chain-level rules are hierarchy-aware, because WithHierarchy is a Routes() option:
If you want the hierarchy-aware check next to the route instead, build a scoped single-rule rule set — authz.Routes returns ordinary middleware, so it goes through the same adapters as everything above (AnyRequest here means “any request that reaches this group”):
authz.Guard is the third option, but it is not middleware — it returns func(ctx, target) error for service-layer calls, where the decision depends on the domain object rather than the path.

Reading the principal

The authentication lives on the request context, so it is always core.MustAuthentication(ctx) — only the way to reach ctx differs:

Fiber

Fiber runs on fasthttp, not net/http, so *fiber.App is not an http.Handler and securityhttp.NewHandler cannot wrap it. Use securityhttp.New to get the chain and mount it with Fiber’s adaptor — middleware.Chain.Then already has the func(http.Handler) http.Handler shape adaptor.HTTPMiddleware expects:
core.MustAuthentication(c.Context()) works because the adaptor copies the request-context values into fasthttp user values, and *fasthttp.RequestCtx — what c.Context() returns — is itself a context.Context whose Value reads them back.
Every other fasthttp-based framework (Atreugo, fasthttp-routing) has the same constraint and the same fix: bridge with an adaptor, and remember that any security middleware you skip on that path is simply not running.

Runnable examples

The repository ships one small program per framework — same routes, same security options, only the framework wiring differs — in a separate Go module so the library itself keeps its standard-library-plus-x/crypto dependency guarantee:
Framework integration walkthrough Each serves GET / (any authenticated user), GET /admin/panel (ADMIN, enforced by the framework’s own route group), GET /csrf, and the POST /login endpoint:
The examples set Secure: false on their cookies so they work over plain HTTP on localhost. In production keep the secure defaults and serve TLS.