authz

package
v0.4.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package authz provides a generic Kratos middleware for authorization. It is engine-agnostic: any Authorizer implementation can be injected.

Example usage:

import (
    pkgauthz "github.com/Servora-Kit/servora/security/authz"
    fgaengine "github.com/Servora-Kit/servora/security/authz/openfga"
)

mw = append(mw, pkgauthz.Server(
    fgaengine.NewAuthorizer(fgaClient),
    pkgauthz.WithRulesFunc(iamv1.AuthzRules),
))

The middleware writes a *auditpb.AuthzDetail to ctx via audit.WithAuthzResult after every Check (allow / deny / error); emission is the responsibility of the transport-tail audit.Collector middleware. The authz package therefore has zero coupling to the audit emission pipeline (only to the neutral auditpb schema package).

Package authz provides a Kratos middleware for relationship-based authorization.

Engine model

The Authorizer interface (Check / BatchCheck / ListAllowed) maps directly onto OpenFGA SDK and SpiceDB primitives. Both ReBAC backends support all three methods natively. The interface is not designed to host non-ReBAC engines (Cedar, Rego); those would require a separate abstraction.

Future: contextual tuples

OpenFGA's "contextual tuples" (and SpiceDB's "caveats") express request-level facts that participate in a decision but are not persisted: device trust, active session, time-of-day, request region, etc.

When this is needed, the planned API is:

ctx = authz.WithContextualTuples(ctx, tuples...)        // upstream mw injects
authz.ContextualTuplesFromContext(ctx) []Tuple          // engine adapter reads

The Authorizer interface signatures already accept context.Context as the first parameter, so no signature change will be required when this is added.

Audit integration

The Server middleware writes a *auditpb.AuthzDetail to ctx via audit.WithAuthzResult after every Authorizer.Check (allow / deny / error). An OUTER-mounted audit.Collector middleware (from obs/audit) reads the detail post-handler and emits the AUTHZ_DECISION event. This package has zero coupling to the audit emission pipeline — only to the neutral auditpb schema package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MergeRules

func MergeRules(ms ...map[string]AuthzRule) map[string]AuthzRule

MergeRules merges multiple AuthzRule maps into one new map. Later maps take precedence on key conflicts (which should not occur in practice). Useful when a server registers services from multiple generated packages.

func Server

func Server(authorizer Authorizer, opts ...Option) middleware.Middleware

Server returns a Kratos middleware that performs authorization checks.

Behavior:

  • No transport in context → passthrough (non-server calls); no ctx detail written.
  • No rule for operation → fail-closed (403 AUTHZ_NO_RULE); no ctx detail written (Authorizer was not invoked, so there is no decision to record).
  • No rule + WithFailOpenOnMissingRule set → alertFn invoked, handler called; no ctx detail written (same reason).
  • AUTHZ_MODE_NONE → skip (public endpoint); no ctx detail written.
  • AUTHZ_MODE_CHECK, no actor or anonymous actor → 403 AUTHZ_DENIED; no ctx detail written (Authorizer was not invoked).
  • AUTHZ_MODE_CHECK, nil authorizer → 503 AUTHZ_UNAVAILABLE; no ctx detail written.
  • AUTHZ_MODE_CHECK, authorizer returned (true, nil) → ALLOWED detail in ctx; handler called.
  • AUTHZ_MODE_CHECK, authorizer returned (false, nil) → DENIED detail in ctx; middleware returns 403 AUTHZ_DENIED.
  • AUTHZ_MODE_CHECK, authorizer returned (_, err) → ERROR detail in ctx (with ErrorReason=err.Error()); middleware returns 503 AUTHZ_CHECK_FAILED.

In all three Authorizer-invoked outcomes the ctx detail is written BEFORE returning, so an OUTER-mounted audit.Collector can observe it post-handler even when authz short-circuits.

The OpenFGA principal is constructed as "<actor.Type()>:<actor.ID()>".

Types

type Authorizer

type Authorizer interface {
	// Check returns whether subject has relation on objectType:objectID.
	Check(ctx context.Context, subject, relation, objectType, objectID string) (allowed bool, err error)

	// BatchCheck runs N checks in one round-trip; output order matches input.
	// Implementations may internally chunk if the backend has per-call limits
	// (OpenFGA caps at 50 per request).
	BatchCheck(ctx context.Context, reqs []CheckRequest) ([]CheckResult, error)

	// ListAllowed returns IDs of objects (of objectType) the subject has the
	// given relation to. The returned strings are bare IDs without "type:" prefix.
	// Useful for "list" endpoints — caller fetches by `WHERE id IN (...)`.
	ListAllowed(ctx context.Context, subject, relation, objectType string) ([]string, error)
}

Authorizer is the interface for relationship-based authorization decisions. All three methods are required: implementations targeting non-ReBAC backends (e.g. pure Cedar/Rego) would need a different abstraction entirely, so we commit to the ReBAC shape rather than a sub-interface fan-out.

Method names match OpenFGA SDK semantics for direct mapping; SpiceDB (LookupResources / BulkCheck) maps cleanly as well.

type AuthzRule

type AuthzRule struct {
	Mode       authzpb.AuthzMode
	Relation   string
	ObjectType string
	// IDField is the proto field name to extract object ID from the request.
	// When empty, "default" is used as the object ID (singleton/platform-level checks).
	IDField string
}

AuthzRule describes the authorization requirement for a single RPC operation.

type CheckRequest added in v0.4.0

type CheckRequest struct {
	Subject    string
	Relation   string
	ObjectType string
	ObjectID   string
}

CheckRequest is one item in a BatchCheck call.

type CheckResult added in v0.4.0

type CheckResult struct {
	Allowed bool
	Err     error
}

CheckResult is the per-item outcome of BatchCheck. Order matches the input []CheckRequest index.

type Option

type Option func(*serverConfig)

Option configures the Server middleware.

func WithCheckTimeout added in v0.4.0

func WithCheckTimeout(d time.Duration) Option

WithCheckTimeout bounds the time spent in Authorizer.Check on each request. Zero (default) disables the deadline — the upstream context applies.

This protects business-RPC latency from a slow authorization backend (e.g. OpenFGA cross-region calls).

func WithDefaultObjectID

func WithDefaultObjectID(id string) Option

WithDefaultObjectID overrides the fallback object ID used when IDField is empty. Defaults to "default".

func WithFailOpenOnMissingRule added in v0.4.0

func WithFailOpenOnMissingRule(alertFn func(ctx context.Context, operation string)) Option

WithFailOpenOnMissingRule changes the missing-rule policy from fail-closed (default — return AUTHZ_NO_RULE 403) to fail-open: the handler is called, and the alertFn callback is invoked so the gap is visible (oncall page, Slack, log warning, etc.).

Use during development or staged rollouts. NEVER use in production for security-sensitive services.

func WithRules

func WithRules(rules map[string]AuthzRule) Option

WithRules sets the operation→rule mapping directly.

func WithRulesFunc

func WithRulesFunc(fn func() map[string]AuthzRule) Option

WithRulesFunc sets the operation→rule mapping via a single function (e.g. generated AuthzRules()). The function is called once during middleware construction. To merge rules from multiple packages, prefer WithRulesFuncs.

func WithRulesFuncs

func WithRulesFuncs(fns ...func() map[string]AuthzRule) Option

WithRulesFuncs merges the rule maps returned by one or more generator functions (e.g. userpb.AuthzRules, authnpb.AuthzRules) into a single rule set. Later entries take precedence on key conflicts (which should not occur in practice). This is the preferred alternative to combining WithRules + MergeRules.

Directories

Path Synopsis
Package noop provides a no-op Authorizer that always permits all requests.
Package noop provides a no-op Authorizer that always permits all requests.
Package openfga provides an OpenFGA-based Authorizer implementation for pkg/authz.
Package openfga provides an OpenFGA-based Authorizer implementation for pkg/authz.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL