Skip to content
Zever
Home

Authorization

Guard routes and RPCs with allow or deny checks using noop, RBAC, or Casbin.

1 min readEdit on GitHub

permission answers what a caller may do through Can(subject, action, resource), returning allow, implicit_deny, or explicit_deny. Adapters: noop (permission/noop, default, denies all), rbac (permission/rbac), casbin (permission/casbin); identity comes from Authentication.

The default noop denies every check with implicit_deny: a placeholder until real policies exist, never for a protected deployment.

Terminal window
PERMISSION_ADAPTER=rbac
Terminal window
PERMISSION_ADAPTER=rbac
main.go
p, err := c.Permission()
if err != nil {
return err // config invalid or policy files unreadable
}

rbac does in-memory role checks from rules (role, action, effect, owned_only) and roles; casbin reads model_path and policy_path (set together, and rules must then be empty) (reference).

authz has no container accessor; it composes Auth() and Permission(). HTTP takes a Policy and a resource-ID extractor, gRPC a method-policy map.

guard.go
authn, err := c.Auth()
if err != nil {
return err
}
checker, err := c.Permission()
if err != nil {
return err
}
pol := authz.Policy{AuthRequired: true, PermissionCheck: "spaces.read", ResourceType: "space"}
guarded := authz.Middleware(authn, checker, pol, func(r *http.Request) string {
return r.PathValue("id")
})(handler)
policies := map[string]authz.Policy{
"/booking.BookingService/Book": {AuthRequired: true, PermissionCheck: "bookings.write", ResourceType: "booking"},
}
guardedUnary := authz.UnaryServerInterceptor(authn, checker, policies)

Valid-token, matching-grant requests reach the handler; others are denied. A Can error means the system failed, so treat it as a denial. gRPC reads the resource id from ResourceIDer; GetId (not GetID) matches the protoc-gen-go getter, so generated request types satisfy it:

type ResourceIDer interface {
GetId() string
}

Decisions are allow, implicit_deny (no rule matched), or explicit_deny (a rule refused); the last two, plus unknown roles and missing policies, fail closed. model_path and policy_path reject .. and must exist at Open.

  • Replace noop before any protected deployment and audit the adapter value.
  • Deny on unknown answers and checker errors too.
  • Never add a method to the public Checker interface; add a smaller one.
  • Keep policy files in version control and sync them across instances.
Every request is denied

The adapter is still noop. Set PERMISSION_ADAPTER=rbac (or casbin).

Open fails on policy paths

The path uses .. or does not exist; use a repo-relative path that exists at startup.

Denials for valid roles

The role or resource differs from the policy (case, prefix, plural); compare exact Can arguments with the policy file.

Can errors under load

The backing store is unreachable; treat it as a denial and check connectivity.

Authentication · Adapters matrix