AuthzX + Chi
Add authorization to your Chi API in 5 minutes.
Install
go get github.com/authzx/authzx-go
Set up the client
package main
import (
"os"
authzx "github.com/authzx/authzx-go"
"github.com/go-chi/chi/v5"
)
var client = authzx.NewClient(os.Getenv("AUTHZX_API_KEY"))
Create middleware
Chi uses standard net/http middleware — the Go SDK's HTTPMiddleware works directly:
r := chi.NewRouter()
r.Route("/documents/{id}", func(r chi.Router) {
r.Use(client.HTTPMiddleware("document", "read", "X-User-ID"))
r.Get("/", getDocument)
})
Custom middleware
For more control over subject extraction and resource ID:
func AuthzMiddleware(resourceType, action string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get("X-User-ID")
if userID == "" {
http.Error(w, `{"error":"unauthorized"}`, 401)
return
}
resourceID := chi.URLParam(r, "id")
allowed, err := client.Check(r.Context(),
authzx.Subject{ID: userID, Type: "user"},
action,
authzx.Resource{ID: resourceID, Type: resourceType},
)
if err != nil {
http.Error(w, `{"error":"authorization check failed"}`, 500)
return
}
if !allowed {
http.Error(w, `{"error":"forbidden"}`, 403)
return
}
next.ServeHTTP(w, r)
})
}
}
Apply to routes
r := chi.NewRouter()
r.Route("/documents/{id}", func(r chi.Router) {
r.With(AuthzMiddleware("document", "read")).Get("/", getDocument)
r.With(AuthzMiddleware("document", "write")).Put("/", updateDocument)
r.With(AuthzMiddleware("document", "delete")).Delete("/", deleteDocument)
})
Group-level middleware
Protect an entire route group:
r.Route("/admin", func(r chi.Router) {
r.Use(AuthzMiddleware("admin-panel", "access"))
r.Get("/users", listUsers)
r.Get("/settings", getSettings)
})
Full response with reason
func getDocument(w http.ResponseWriter, r *http.Request) {
resp, err := client.Authorize(r.Context(), &authzx.AuthorizeRequest{
Subject: authzx.Subject{ID: r.Header.Get("X-User-ID")},
Resource: authzx.Resource{ID: chi.URLParam(r, "id"), Type: "document"},
Action: "read",
})
if err != nil {
http.Error(w, `{"error":"authorization failed"}`, 500)
return
}
if !resp.Allowed {
w.WriteHeader(403)
json.NewEncoder(w).Encode(map[string]string{"error": "forbidden", "reason": resp.Reason})
return
}
json.NewEncoder(w).Encode(map[string]string{
"id": chi.URLParam(r, "id"),
"policy": resp.PolicyID,
"path": resp.AccessPath,
})
}
Using the local agent
var client = authzx.NewClient("", authzx.WithBaseURL("http://localhost:8181"))
No API key needed. Same middleware, sub-millisecond responses.