Help us shape the future of Go! Take the 2026 Go Developer Survey

authorization

package module
v3.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 14 Imported by: 0

README

authorization

CI CodeQL Coverage Mutation Documentation Go Reference Release Go License

authorization is an application-oriented authorization engine for typed Go policies. It uses explicit ACL, RBAC, and ABAC models rather than a positional string meta-model or separate policy language.

Unreleased decision and lifecycle boundaries

NewDecisionService optionally wraps an existing Authorizer with an exact positive DecisionContext.PolicyRevision fence, defensive input/output copies and post-callback cancellation checks. Stale revisions, invalid outcomes, dependency failures and panics cannot authorize. The existing engine keeps its own API and request-borrowing semantics.

postgres.AuthoritySchemaMigration separately allocates forward-only lifecycle epoch storage without changing the manifest schema. Native transaction owners explicitly initialize and advance exact tenant/namespace/subject epochs and hold RequireAuthority share locks through their protected effect. Primary reads never bootstrap rows. Returned epochs are structural metadata, not a renewable freshness lease or an independently committed administrative action. These additions are not part of the existing v3.0.0 release.

The current implementation includes:

  • typed requests, decisions, reason codes, and policy identities;
  • deny-overrides, allow-overrides, first-applicable, and priority-order composition;
  • structurally immutable revisioned snapshots with atomic optimistic replacement and borrowed reusable evaluators;
  • bounded batch evaluation and bounded explanation traces;
  • activation windows, fail-closed errors, and default deny;
  • typed, indexed ACL evaluation and resource-ID listing;
  • tenant-safe RBAC with bounded inheritance and assignment administration;
  • closed, typed ABAC conditions with deterministic cost and depth budgets;
  • policy diff, dry-run, and a strict versioned JSON persistence envelope;
  • bounded manifest compilation through an explicit model decoder registry;
  • strict versioned ACL, RBAC, and ABAC model documents for activation;
  • atomic PostgreSQL manifest persistence with optimistic revision checks and a reusable migrations migration;
  • advisory Valkey revision hints with pub/sub wakeups and key polling, subject to backend numeric ranges and deployment-owned durability;
  • direct source-of-truth synchronization independent of cache publication;
  • dependency-neutral authenticated-principal mapping;
  • fail-closed adapters/http and native adapters/jsonrpc integration;
  • adapters/slog audit and adapters/otel metrics/trace adapters with wrapper-enforced metadata count caps and caller-owned text privacy; and
  • explicit advisory adapters/cache manifest integration.

See the five-minute ACL quickstart and five-minute RBAC quickstart, plus the five-minute ABAC quickstart. Model decoders and the standard HTTP integration are deliberately interface-based so applications can add framework-specific adapters without changing policy semantics.

The complete guide map is in the documentation index. For a compiled multi-model application, see the tenant documents example.

Policy composition and portable format contracts are documented in policy composition and policy format compatibility. PostgreSQL setup and atomic update semantics are covered in PostgreSQL persistence. Cross-process invalidation is covered in Valkey invalidation.

Authentication mapping and transport behavior are documented in authentication integration, HTTP integration, and JSON-RPC integration. Audit, telemetry, and cache boundaries are covered in observability and cache integration. The released authcache, authhttp, httpauth, authlog, authotel, and authrpc paths remain supported compatibility paths during their documented migration interval. Reusable fixtures, assertions, decision snapshots, and integration conformance checks are documented in authorization testing. Default resource bounds, the benchmark matrix, reference measurements, and scaling guidance are documented in performance and limits.

For ecosystem-wide construction, ownership, lifecycle, and composition guidance, see the versioned Golib ecosystem index and its Service edge family.

Use Go 1.27.2 for development and start with GOWORK=off go test ./.... Install the public golib release declared in .golib.yaml without building it from source. make check/make ci run bounded checks across both catalog modules, retaining PostgreSQL and Valkey prerequisites plus a selected snapshot-consistency race. Base-free checks run fuzz seeds/corpus, not active campaigns; make check-full retains the original full contract. Direct integration tests run when POSTGRES_URL or VALKEY_ADDRESS is configured and otherwise skip without contacting local services.

Security boundaries and operational assumptions are documented in the threat model. See SECURITY.md for private reporting guidance and CONTRIBUTING.md for local quality gates. The package is licensed under the MIT License.

Documentation

Start with the documentation index for model selection, integration, persistence, operations, and security guidance.

Documentation navigation

Complete documentation map · Current source package map

Use the versioned ecosystem entry for package selection. The frozen compatibility cohort is separate from current package releases and unpublished source changes. Adopting them does not silently update that cohort.

Documentation

Overview

Package authorization evaluates caller-mapped identities, actions, resources and facts against explicit policy snapshots. NewSnapshot/NewEngine establish coherent low-level evaluation; ACL, RBAC and ABAC provide local models, while policy owns portable manifests and optional synchronization. Engine converts no-match to deny; standalone models may return NotApplicable.

Authentication, tenant membership, attribute authority, policy administration and resource fetching belong to the application. Requests and evaluators are borrowed, not deep-copied or sandboxed; collaborators must remain immutable, concurrency-safe and cooperative. No watcher or background worker is started by the core. Optional adapters introduce their own borrowed backend/SDK seams. Diagnostic count caps do not sanitize or bound arbitrary identifier strings.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidCombiningAlgorithm indicates an unsupported combining algorithm.
	ErrInvalidCombiningAlgorithm = errors.New("invalid combining algorithm")
	// ErrInvalidOutcome indicates a decision with an unsupported outcome.
	ErrInvalidOutcome = errors.New("invalid decision outcome")
)
View Source
var (
	// ErrRevisionConflict identifies authorization revision conflict. Compare with errors.Is, not error text.
	ErrRevisionConflict = errors.New("authorization revision conflict")
	// ErrRevisionNotMonotonic identifies authorization revision is not monotonic. Compare with errors.Is, not error text.
	ErrRevisionNotMonotonic = errors.New("authorization revision is not monotonic")
)
View Source
var (
	// ErrNilAuthorizer identifies authorization instrumented authorizer is nil. Compare with errors.Is, not error text.
	ErrNilAuthorizer = errors.New("authorization instrumented authorizer is nil")
	// ErrNilInstrumenter identifies authorization instrumenter is nil. Compare with errors.Is, not error text.
	ErrNilInstrumenter = errors.New("authorization instrumenter is nil")
	// ErrInvalidInstrumentationConfig identifies authorization instrumentation config is invalid. Compare with errors.Is, not error text.
	ErrInvalidInstrumentationConfig = errors.New("authorization instrumentation config is invalid")
)
View Source
var (
	// ErrInvalidPolicy identifies invalid policy. Compare with errors.Is, not error text.
	ErrInvalidPolicy = errors.New("invalid policy")
	// ErrDuplicatePolicy identifies duplicate policy. Compare with errors.Is, not error text.
	ErrDuplicatePolicy = errors.New("duplicate policy")
	// ErrInvalidActivationWindow identifies invalid policy activation window. Compare with errors.Is, not error text.
	ErrInvalidActivationWindow = errors.New("invalid policy activation window")
	// ErrInvalidRevision identifies invalid policy revision. Compare with errors.Is, not error text.
	ErrInvalidRevision = errors.New("invalid policy revision")
)
View Source
var ErrBatchLimitExceeded = errors.New("authorization batch limit exceeded")

ErrBatchLimitExceeded identifies authorization batch limit exceeded. Compare with errors.Is, not error text.

View Source
var ErrDecisionUnavailable = errors.New("authorization decision unavailable")

ErrDecisionUnavailable is a redacted dependency failure at Service.Decide.

View Source
var ErrInvalidFloat = errors.New("attribute float must be finite")

ErrInvalidFloat identifies attribute float must be finite. Compare with errors.Is, not error text.

View Source
var ErrInvalidRequest = errors.New("invalid authorization request")

ErrInvalidRequest identifies invalid authorization request. Compare with errors.Is, not error text.

View Source
var ErrNilSnapshot = errors.New("authorization snapshot is nil")

ErrNilSnapshot identifies authorization snapshot is nil. Compare with errors.Is, not error text.

View Source
var ErrPolicyLimitExceeded = errors.New("authorization policy limit exceeded")

ErrPolicyLimitExceeded identifies authorization policy limit exceeded. Compare with errors.Is, not error text.

View Source
var ErrPolicyPanic = errors.New("authorization policy panicked")

ErrPolicyPanic identifies authorization policy panicked. Compare with errors.Is, not error text.

Functions

This section is empty.

Types

type Action

type Action string

Action is an exact operation label; no wildcard expansion is implied.

type AttributeName

type AttributeName string

AttributeName is an exact fact-map key, not a nested path.

type Attributes

type Attributes map[AttributeName]Value

Attributes is caller-owned fact state; keep it stable during evaluation and authenticate its sources.

type Authorizer

type Authorizer interface {
	// Decide returns a valid outcome or error; map errors to failure, never allow.
	Decide(context.Context, Request) (Decision, error)
}

Authorizer decides from trusted caller-mapped input. Implementations must cooperate with ctx and support concurrent reuse; this seam performs no authentication.

type BeginInstrumenter

type BeginInstrumenter interface {
	// Begin returns an optional derived context and completion callback; preserve caller cancellation.
	Begin(context.Context) (context.Context, func(Event))
}

BeginInstrumenter starts one bounded authorization observation.

type CombiningAlgorithm

type CombiningAlgorithm uint8

CombiningAlgorithm determines how multiple policy decisions are resolved.

const (
	// DenyOverrides prefers any explicit deny over allows.
	DenyOverrides CombiningAlgorithm = iota
	// AllowOverrides prefers any explicit allow over denies.
	AllowOverrides
	// FirstApplicable selects the first non-NotApplicable input in definition order.
	FirstApplicable
	// PriorityOrder selects the first applicable policy after Snapshot sorts descending priority then ID.
	PriorityOrder
)

func (CombiningAlgorithm) String

func (algorithm CombiningAlgorithm) String() string

String returns the stable name of a combining algorithm.

type Decision

type Decision struct {
	// Outcome is Allow, Deny or NotApplicable; Engine validates and default-denies.
	Outcome Outcome
	// Reason is caller/model-defined diagnostic text; it must not contain secrets.
	Reason ReasonCode
	// MatchedPolicyIDs preserves match order; count caps do not bound identifier bytes.
	MatchedPolicyIDs []PolicyID
	// MatchedPolicyIDsTruncated signals incomplete identifier diagnostics, not changed outcome.
	MatchedPolicyIDsTruncated bool
	// Revision identifies the declared policy/view generation; it is not an authenticity signature.
	Revision Revision
	// Trace contains evaluation-order metadata without dedicated request-value fields.
	Trace []TraceEntry
	// TraceTruncated signals incomplete trace diagnostics.
	TraceTruncated bool
}

Decision is the result of one or more policy evaluations.

func Combine

func Combine(algorithm CombiningAlgorithm, decisions []Decision) (Decision, error)

Combine validates all supplied outcomes, then selects the decisive/last applicable Decision. Deny/AllowOverrides prefer their named outcome; ordered algorithms take the first applicable input. PriorityOrder does not sort here; NewSnapshot owns priority ordering. Empty/all-inapplicable input stays NotApplicable; only Engine applies default-deny. The selected decision's slices are shared, not merged/copied, and no context/resource admission is performed.

type DecisionContext added in v3.1.0

type DecisionContext struct {
	// Request is the complete policy input; callers keep it stable while copied.
	Request Request
	// CorrelationID is optional diagnostic correlation, never policy authority.
	CorrelationID string
	// PolicyRevision is the exact positive revision that may authorize this call.
	PolicyRevision Revision
}

DecisionContext binds a complete request to one positive immutable policy revision. Optional CorrelationID is limited to 128 valid UTF-8 bytes. Consumers own their stricter entry/encoded-size admission limits.

func (DecisionContext) Clone added in v3.1.0

func (decisionContext DecisionContext) Clone() DecisionContext

Clone copies all request-owned maps and slices; immutable Value data is shared.

func (DecisionContext) Validate added in v3.1.0

func (decisionContext DecisionContext) Validate() error

Validate rejects incomplete requests, zero revisions and invalid correlation IDs.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine evaluates each request/batch against one captured snapshot and permits concurrent Decide/ReplaceSnapshot calls. Evaluators, clocks and input graphs must support that reuse; only publication/state replacement is synchronized. Construct with NewEngine; the zero Engine is unusable. No goroutine, timer, source refresh or evaluator shutdown is owned.

func NewEngine

func NewEngine(snapshot *Snapshot, options ...EngineOption) (*Engine, error)

NewEngine borrows a non-nil snapshot, applies options synchronously and checks the selected policy count cap. A non-nil but unvalidated zero Snapshot is not rejected here. Nil/custom options can panic and must not retain mutable Engine access for later changes. Default limits are 1000 requests/policies and 100 trace/matched IDs; count caps do not bound strings or collaborator work.

func (*Engine) Decide

func (engine *Engine) Decide(ctx context.Context, request Request) (Decision, error)

Decide validates required request strings, captures one snapshot, then evaluates active policies until the combining algorithm is decisive. No-match becomes deny. Activation time uses supplied Environment.Time or one clock sample. Errors/panics in evaluators deny, but raw error causes remain inspectable. Context checks occur before each policy, not after a final successful callback; callbacks are cooperative. Request maps/groups are borrowed; ctx and receiver must be usable/non-nil.

func (*Engine) DecideBatch

func (engine *Engine) DecideBatch(
	ctx context.Context,
	requests []Request,
) ([]Decision, error)

DecideBatch evaluates in input order against one captured snapshot. Oversize input returns nil before allocation/evaluation. Otherwise every request gets a result and failures are joined; later requests still run, including after cancellation (their owned checks may deny). Request graphs remain borrowed, callback effects are not transactional, and an empty batch performs no ctx check.

func (*Engine) ReplaceSnapshot

func (engine *Engine) ReplaceSnapshot(next *Snapshot, expected Revision) error

ReplaceSnapshot atomically installs a newer snapshot when the caller's expected revision still matches the active view. The local replacement mutex serializes the revision check/store; existing calls finish on the old snapshot. This does not persist policy, invalidate other processes or close old evaluators.

func (*Engine) Revision

func (engine *Engine) Revision() Revision

Revision returns the revision of the snapshot currently used for new decisions.

type EngineOption

type EngineOption func(*Engine)

EngineOption configures construction synchronously; custom/nil options are trusted and may panic.

func WithClock

func WithClock(clock func() time.Time) EngineOption

WithClock supplies time when a request omits Environment.Time; nil is ignored. The borrowed clock runs inline, must be concurrency-safe/prompt and must not panic. Clock failures are not inside evaluator panic recovery.

func WithLimits

func WithLimits(limits Limits) EngineOption

WithLimits configures positive limits and leaves zero-valued fields at safe defaults; negative as well as zero fields are ignored.

type Environment

type Environment struct {
	// Time is caller-supplied evaluation time; zero lets Engine sample its clock.
	Time time.Time
	// Attributes is the caller-owned fact map; sensitivity/authority is not inferred.
	Attributes Attributes
}

Environment contains deterministic request-scoped evaluation inputs.

type Evaluator

type Evaluator interface {
	// Evaluate returns a valid outcome or an error, using immutable borrowed
	// request data. Decision identifiers/reasons must be non-secret application text.
	Evaluate(context.Context, Request) (Decision, error)
}

Evaluator is the bounded, I/O-free decision interface implemented by policy models such as ACL, RBAC, and ABAC. This is a collaborator obligation, not an I/O/CPU sandbox: implementations must cooperate with ctx, avoid input mutation and support concurrent calls when shared. Engine catches evaluation panics but cannot undo side effects or preempt blocking work.

type Event

type Event struct {
	// Outcome is Allow, Deny or NotApplicable; Engine validates and default-denies.
	Outcome Outcome
	// Reason is caller/model-defined diagnostic text; it must not contain secrets.
	Reason ReasonCode
	// Revision identifies the declared policy/view generation; it is not an authenticity signature.
	Revision Revision
	// MatchedPolicyIDs preserves match order; count caps do not bound identifier bytes.
	MatchedPolicyIDs []PolicyID
	// MatchedPolicyIDsTruncated signals incomplete identifier diagnostics, not changed outcome.
	MatchedPolicyIDsTruncated bool
	// TraceCount is the observed number of retained trace entries, not every evaluated policy.
	TraceCount int
	// TraceTruncated signals incomplete trace diagnostics.
	TraceTruncated bool
	// Duration is elapsed instrumentation clock time, clamped nonnegative by the wrapper.
	Duration time.Duration
	// Failed reports a non-nil authorizer error; it does not inspect sensitive cause text.
	Failed bool
}

Event contains bounded decision metadata without subject, resource, tenant, attribute, or policy-document contents as dedicated fields. Reason and policy identifiers are trusted application text, not sanitized or byte-bounded; keep them non-secret. Direct adapter callbacks do not enforce this wrapper's caps.

type InstrumentationConfig

type InstrumentationConfig struct {
	// Clock is borrowed time policy and must be prompt/concurrency-safe; no lifecycle is owned.
	Clock func() time.Time
	// MaxPolicyIDs caps copied event identifiers; zero selects 100, negative is invalid.
	MaxPolicyIDs int
}

InstrumentationConfig selects borrowed clock and copied event-ID count admission, not total logging/tracing bytes or callback duration.

type Instrumented

type Instrumented struct {
	// contains filtered or unexported fields
}

Instrumented is a borrowed authorizer decorator, constructed by either instrumentation constructor; the zero value is unusable and no shutdown is owned.

func NewInstrumented

func NewInstrumented(
	authorizer Authorizer,
	instrumenter Instrumenter,
	config InstrumentationConfig,
) (*Instrumented, error)

NewInstrumented borrows Start-based collaborators and rejects literal nil only. Typed-nil behavior differs from NewInstrumentedWithBegin; custom code must be valid.

func NewInstrumentedWithBegin

func NewInstrumentedWithBegin(
	authorizer Authorizer,
	instrumenter BeginInstrumenter,
	config InstrumentationConfig,
) (*Instrumented, error)

NewInstrumentedWithBegin constructs an authorizer using the common Begin observation lifecycle. Literal and typed-nil dependencies are rejected before any decision work begins. The underlying authorizer/callbacks are borrowed. No provider shutdown or export scheduling is owned.

func (*Instrumented) Decide

func (instrumented *Instrumented) Decide(
	ctx context.Context,
	request Request,
) (Decision, error)

Decide observes one inline authorizer call without changing its returned decision/error. Observation clock/start/finish panics are contained; blocking callbacks are not preempted. Authorizer panics bypass normal completion, so an observation/span may remain unfinished. Finish gets a copied capped ID slice, while the returned decision remains borrowed from the authorizer. A derived context may change cancellation; Start/Begin must preserve caller obligations.

type Instrumenter

type Instrumenter interface {
	// Start returns an optional derived context and completion callback, without owning authorization.
	Start(context.Context) (context.Context, func(Event))
}

Instrumenter starts synchronous observation using borrowed context/state. Derived contexts must preserve cancellation and metadata obligations; finish callbacks may block, so callers must keep them cooperative/concurrency-safe.

type Limits

type Limits struct {
	// MaxBatchSize admits request count before result allocation; default is 1000.
	MaxBatchSize int
	// MaxPolicies admits policy count; default is 1000, not a total byte budget.
	MaxPolicies int
	// MaxTraceSize caps trace entry count; default is 100.
	MaxTraceSize int
	// MaxMatchedPolicyIDs caps accumulated identifier count; default is 100.
	MaxMatchedPolicyIDs int
}

Limits bounds work and diagnostic cardinality for one engine.

type Outcome

type Outcome uint8

Outcome is the result of evaluating an authorization policy.

const (
	// NotApplicable means no applicable policy; Engine converts the final result to default deny.
	NotApplicable Outcome = iota
	// Allow is an explicit grant; adapters forward only this valid outcome.
	Allow
	// Deny is an explicit refusal.
	Deny
)

func (Outcome) String

func (outcome Outcome) String() string

String returns a stable outcome label, or unknown for an invalid value.

type PolicyDefinition

type PolicyDefinition struct {
	// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
	ID PolicyID
	// Revision identifies the declared policy/view generation; it is not an authenticity signature.
	Revision Revision
	// Priority orders higher values first where the selected model supports ordering.
	Priority int
	// ActiveFrom starts the inclusive activation window; absent/zero means unbounded.
	ActiveFrom time.Time
	// ActiveUntil ends the exclusive activation window; absent/zero means unbounded.
	ActiveUntil time.Time
	// Metadata contains editable application labels, not authenticated/private storage.
	Metadata map[string]string
	// Evaluator is borrowed and must be immutable/concurrency-safe/cooperative when shared.
	Evaluator Evaluator
}

PolicyDefinition binds a stable policy identity to its evaluator.

type PolicyEvaluationError

type PolicyEvaluationError struct {
	// PolicyID is the exact non-secret policy diagnostic identity.
	PolicyID PolicyID
	// Err is a borrowed error cause; deliberate unwrapping/fixture use can expose its text/type.
	Err error
}

PolicyEvaluationError identifies a failed policy without exposing its internal error text. Unwrap retains programmatic error inspection.

func (*PolicyEvaluationError) Error

func (evaluationError *PolicyEvaluationError) Error() string

Error prints the trusted policy ID, not the evaluator cause text.

func (*PolicyEvaluationError) Unwrap

func (evaluationError *PolicyEvaluationError) Unwrap() error

Unwrap exposes the original evaluator cause; protect deliberate inspection/logging.

type PolicyID

type PolicyID string

PolicyID is an exact policy diagnostic label; keep it non-secret.

type PolicyInfo

type PolicyInfo struct {
	// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
	ID PolicyID
	// Revision identifies the declared policy/view generation; it is not an authenticity signature.
	Revision Revision
	// Priority orders higher values first where the selected model supports ordering.
	Priority int
	// ActiveFrom starts the inclusive activation window; absent/zero means unbounded.
	ActiveFrom time.Time
	// ActiveUntil ends the exclusive activation window; absent/zero means unbounded.
	ActiveUntil time.Time
	// Metadata contains editable application labels, not authenticated/private storage.
	Metadata map[string]string
}

PolicyInfo is inspectable copied metadata for one snapshotted policy. It is not sanitized; callers must keep labels and metadata non-secret.

type ReasonCode

type ReasonCode string

ReasonCode is diagnostic text, not a closed enum; keep it non-secret.

const (
	// ReasonDefaultDeny marks an engine result with no applicable grant.
	ReasonDefaultDeny ReasonCode = "default-deny"
	// ReasonInvalidRequest marks failed Engine request validation.
	ReasonInvalidRequest ReasonCode = "invalid-request"
	// ReasonEvaluationError marks failed or invalid evaluator output.
	ReasonEvaluationError ReasonCode = "evaluation-error"
	// ReasonContextCanceled marks cancellation observed by Engine.
	ReasonContextCanceled ReasonCode = "context-canceled"
	// ReasonPolicyInactive marks a policy skipped outside its activation window.
	ReasonPolicyInactive ReasonCode = "policy-inactive"
	// ReasonPolicyStale marks rejected repository-freshness admission.
	ReasonPolicyStale ReasonCode = "policy-stale"
)

type Request

type Request struct {
	// Subject supplies trusted kind/ID and optional group/fact state; it is not authenticated here.
	Subject Subject
	// Action is matched byte-for-byte; no wildcard, normalization or permission discovery is implied.
	Action Action
	// Resource carries exact type/optional instance ID and borrowed application facts.
	Resource Resource
	// Tenant is exact scope; empty means global, not inferred tenant membership.
	Tenant TenantID
	// Environment supplies caller-mapped time/facts; Engine does not authenticate them.
	Environment Environment
	// Attributes is the caller-owned fact map; sensitivity/authority is not inferred.
	Attributes Attributes
}

Request contains the stable, typed inputs shared by every policy model. An empty tenant denotes an explicitly global request scope. Maps/groups are borrowed and must not be mutated during evaluation, including by custom evaluators. No authentication or automatic tenant binding is performed.

func (Request) Validate

func (request Request) Validate() error

Validate rejects empty subject kind/ID, action, resource type and group IDs. It does not authenticate identity, validate known kind enums, trim strings, admit map/group/identifier bytes or verify tenant/resource/attribute authority. Resource.ID and Tenant may be empty for type-wide/global scope. Models used directly need their own admission; Engine calls Validate before evaluation.

type Resource

type Resource struct {
	// Type is the exact application resource-type label, not an external schema lookup.
	Type ResourceType
	// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
	ID ResourceID
	// Attributes is the caller-owned fact map; sensitivity/authority is not inferred.
	Attributes Attributes
}

Resource identifies either a resource type or a concrete resource instance. An empty ID intentionally represents the entire resource type.

type ResourceID

type ResourceID string

ResourceID is an exact instance label; empty denotes type-wide scope.

type ResourceType

type ResourceType string

ResourceType is an exact application resource category.

type Revision

type Revision uint64

Revision is a caller-assigned uint64 generation; no overflow, authenticity or backend-range validation is implicit.

type Service added in v3.1.0

type Service interface {
	// Decide returns only revision-matched Allow or Deny; errors never authorize.
	Decide(context.Context, DecisionContext) (Decision, error)
}

Service is the revision-fenced decision boundary. Implementations must fail closed on errors, stale revisions, NotApplicable and invalid outcomes. Calls accept bounded caller contexts; implementations document concurrent safety.

func NewDecisionService added in v3.1.0

func NewDecisionService(authorizer Authorizer) (Service, error)

NewDecisionService adapts an existing Authorizer without changing its API. It rejects nil/typed-nil dependencies, copies inputs/outputs and grants only explicit Allow at the requested revision without error. It owns no goroutines, stores or locks; the supplied Authorizer must support concurrent calls.

Example
package main

import (
	"context"
	"fmt"

	authorization "github.com/faustbrian/go-authorization/v3"
)

func main() {
	snapshot, _ := authorization.NewSnapshot(1, authorization.DenyOverrides)
	engine, _ := authorization.NewEngine(snapshot)
	service, _ := authorization.NewDecisionService(engine)
	decision, err := service.Decide(context.Background(), authorization.DecisionContext{Request: authorization.Request{Subject: authorization.Subject{Kind: authorization.SubjectUser, ID: "user"}, Action: "read", Resource: authorization.Resource{Type: "document"}}, PolicyRevision: 1})
	fmt.Println(decision.Outcome, err)
}
Output:
deny <nil>

type Snapshot

type Snapshot struct {
	// contains filtered or unexported fields
}

Snapshot fixes policy order/activation metadata for a coherent decision. Metadata maps are copied, but Evaluator instances are borrowed and must be immutable/concurrency-safe. Structural immutability is not deep evaluator isolation or authentication. Construct with NewSnapshot; the zero/nil view is not a validated revisioned snapshot.

func NewSnapshot

func NewSnapshot(
	revision Revision,
	algorithm CombiningAlgorithm,
	definitions ...PolicyDefinition,
) (*Snapshot, error)

NewSnapshot requires nonzero revision, a supported algorithm and unique nonempty IDs/literal-non-nil evaluators. Typed-nil evaluators are not detected. Zero per-policy revisions inherit the snapshot revision; other revisions need not equal it. Activation is [ActiveFrom, ActiveUntil), with zero ends unbounded. PriorityOrder sorts descending priority then lexical ID; other algorithms preserve definition order. Metadata maps are copied; evaluators are borrowed. Policy count/string/callback admission belongs to callers and Engine limits.

func (*Snapshot) Algorithm

func (snapshot *Snapshot) Algorithm() CombiningAlgorithm

Algorithm returns the snapshot's validated combining algorithm.

func (*Snapshot) Policies

func (snapshot *Snapshot) Policies() []PolicyInfo

Policies returns a defensive copy of inspectable policy metadata.

func (*Snapshot) Revision

func (snapshot *Snapshot) Revision() Revision

Revision returns the immutable snapshot revision.

type Subject

type Subject struct {
	// Kind is the caller-selected representation/category, not an authentication assertion.
	Kind SubjectKind
	// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
	ID SubjectID
	// Groups is trusted mapped membership; request slices are borrowed during evaluation.
	Groups []SubjectID
	// Attributes is the caller-owned fact map; sensitivity/authority is not inferred.
	Attributes Attributes
}

Subject identifies the principal making an authorization request.

type SubjectID

type SubjectID string

SubjectID is an exact caller-defined principal label, not a credential.

type SubjectKind

type SubjectKind string

SubjectKind identifies the application-defined kind of principal.

const (
	// SubjectUser labels a user principal without verifying its identity.
	SubjectUser SubjectKind = "user"
	// SubjectServiceAccount labels a service-account principal without verifying its identity.
	SubjectServiceAccount SubjectKind = "service-account"
	// SubjectAPIKey labels an API-key principal, not the secret key bytes.
	SubjectAPIKey SubjectKind = "api-key"
	// SubjectGroup labels a group principal; request groups still require trusted membership.
	SubjectGroup SubjectKind = "group"
)

type TenantID

type TenantID string

TenantID is an exact scope label; empty denotes global scope, not membership verification.

type TraceEntry

type TraceEntry struct {
	// PolicyID is the exact non-secret policy diagnostic identity.
	PolicyID PolicyID
	// Outcome is Allow, Deny or NotApplicable; Engine validates and default-denies.
	Outcome Outcome
	// Reason is caller/model-defined diagnostic text; it must not contain secrets.
	Reason ReasonCode
}

TraceEntry records one policy result without request or attribute values.

type ValidationError

type ValidationError struct {
	// Field is the failed-input path printed by Error; keep manually supplied text non-secret.
	Field string
}

ValidationError records a failed input path. Validate supplies known field names, not input values; a manually supplied Field remains unredacted.

func (*ValidationError) Error

func (validationError *ValidationError) Error() string

Error formats Field with ErrInvalidRequest; it does not redact custom Field text.

func (*ValidationError) Unwrap

func (validationError *ValidationError) Unwrap() error

Unwrap exposes ErrInvalidRequest for errors.Is.

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is an immutable typed attribute value. Its zero value represents an invalid or missing value and is distinct from explicit null.

func BoolValue

func BoolValue(value bool) Value

BoolValue wraps a boolean without coercion.

func FloatValue

func FloatValue(value float64) (Value, error)

FloatValue rejects NaN/infinities with ErrInvalidFloat; finite values are retained.

func IPValue

func IPValue(value netip.Addr) Value

IPValue normalizes IPv4-mapped addresses with Unmap; invalid addresses remain invalid.

func IntValue

func IntValue(value int64) Value

IntValue wraps a signed 64-bit integer without coercion.

func MustFloatValue

func MustFloatValue(value float64) Value

MustFloatValue returns FloatValue or panics with ErrInvalidFloat; use only for trusted constants.

func NullValue

func NullValue() Value

NullValue returns explicit null, distinct from the zero missing Value.

func StringSetValue

func StringSetValue(values []string) Value

StringSetValue copies, sorts lexically and deduplicates values before returning immutable set state; no input/cardinality/byte cap is enforced.

func StringValue

func StringValue(value string) Value

StringValue retains text without copying, normalization or byte admission.

func TimeValue

func TimeValue(value time.Time) Value

TimeValue drops monotonic data and normalizes the instant to UTC.

func (Value) Bool

func (value Value) Bool() (bool, bool)

Bool returns the stored boolean and whether that representation is present.

func (Value) CollectionLength

func (value Value) CollectionLength() (int, bool)

CollectionLength reports the cardinality of collection values.

func (Value) Compare

func (value Value) Compare(other Value) (int, bool)

Compare orders strings, integers, finite floats and times of the same kind. Other/cross-kind pairs return (0, false); no numeric/string coercion occurs.

func (Value) Equal

func (value Value) Equal(other Value) bool

Equal reports structural equality without type coercion.

func (Value) Float

func (value Value) Float() (float64, bool)

Float returns the stored finite float and whether that representation is present.

func (Value) IP

func (value Value) IP() (netip.Addr, bool)

IP returns the stored unmapped address and whether that representation is present.

func (Value) Int

func (value Value) Int() (int64, bool)

Int returns the stored int64 and whether that representation is present.

func (Value) Kind

func (value Value) Kind() ValueKind

Kind reports the representation; zero is ValueMissing.

func (Value) String

func (value Value) String() (string, bool)

String returns stored text and whether the value is a string.

func (Value) StringSet

func (value Value) StringSet() ([]string, bool)

StringSet returns a copied sorted/deduplicated slice, or (nil, false) for a non-set.

func (Value) Time

func (value Value) Time() (time.Time, bool)

Time returns the stored UTC instant and whether that representation is present.

type ValueKind

type ValueKind uint8

ValueKind is the closed set of supported attribute representations.

const (
	// ValueMissing is the zero/missing representation, distinct from null.
	ValueMissing ValueKind = iota
	// ValueNull is explicit null.
	ValueNull
	// ValueString is exact text.
	ValueString
	// ValueBool is a boolean.
	ValueBool
	// ValueInt is a signed 64-bit integer.
	ValueInt
	// ValueFloat is a finite float64.
	ValueFloat
	// ValueTime is a UTC instant without monotonic data.
	ValueTime
	// ValueIP is an unmapped netip address, possibly invalid.
	ValueIP
	// ValueStringSet is an immutable sorted deduplicated string set.
	ValueStringSet
)

Directories

Path Synopsis
Package abac evaluates a closed typed expression model over caller-owned facts.
Package abac evaluates a closed typed expression model over caller-owned facts.
Package acl indexes explicit subject/group grants and denials by action and resource type.
Package acl indexes explicit subject/group grants and denials by action and resource type.
adapters
cache
Package authorizationcache provides explicit advisory cache adapters for portable policy manifests.
Package authorizationcache provides explicit advisory cache adapters for portable policy manifests.
http
Package authorizationhttp provides fail-closed net/http authorization integration.
Package authorizationhttp provides fail-closed net/http authorization integration.
jsonrpc
Package authorizationjsonrpc provides fail-closed JSON-RPC authorization middleware.
Package authorizationjsonrpc provides fail-closed JSON-RPC authorization middleware.
otel
Package authorizationotel records authorization metrics and traces through explicit OpenTelemetry v1.47.0 providers.
Package authorizationotel records authorization metrics and traces through explicit OpenTelemetry v1.47.0 providers.
slog
Package authorizationslog emits authorization audit events through log/slog.
Package authorizationslog emits authorization audit events through log/slog.
Package authcache provides the legacy authorization cache adapter.
Package authcache provides the legacy authorization cache adapter.
Package authhttp provides the legacy net/http authorization adapter.
Package authhttp provides the legacy net/http authorization adapter.
Package authlog provides the legacy bounded authorization slog adapter.
Package authlog provides the legacy bounded authorization slog adapter.
Package authn maps immutable authenticated principals into authorization subjects without making authentication depend on authorization.
Package authn maps immutable authenticated principals into authorization subjects without making authentication depend on authorization.
Package authorizationtest provides deterministic fixtures, assertions, and selected common-contract checks for authorization integrations.
Package authorizationtest provides deterministic fixtures, assertions, and selected common-contract checks for authorization integrations.
Package authotel provides the legacy authorization OpenTelemetry adapter.
Package authotel provides the legacy authorization OpenTelemetry adapter.
Package authrpc provides the legacy fail-closed JSON-RPC authorization middleware.
Package authrpc provides the legacy fail-closed JSON-RPC authorization middleware.
examples
tenant_documents command
Package main demonstrates composing tenant RBAC, resource ACL, and a trusted ownership attribute under deny-overrides semantics.
Package main demonstrates composing tenant RBAC, resource ACL, and a trusted ownership attribute under deny-overrides semantics.
Package httpauth provides the legacy fail-closed net/http authorization integration.
Package httpauth provides the legacy fail-closed net/http authorization integration.
internal
authorizationotel
Package authorizationotel shares the explicit OpenTelemetry observation implementation used by the direct adapter.
Package authorizationotel shares the explicit OpenTelemetry observation implementation used by the direct adapter.
Package policy owns the application authorization.policy/v1 manifest profile, explicit decoder compilation, inspectable diffs, dry-runs and cooperative reload.
Package policy owns the application authorization.policy/v1 manifest profile, explicit decoder compilation, inspectable diffs, dry-runs and cooperative reload.
Package postgres persists a complete manifest in one PostgreSQL singleton row.
Package postgres persists a complete manifest in one PostgreSQL singleton row.
Package rbac resolves exact-scope subject/group assignments through a validated acyclic role graph.
Package rbac resolves exact-scope subject/group assignments through a validated acyclic role graph.
Package valkey distributes monotonic policy revision invalidations through Valkey as advisory hints, not authorization or policy content.
Package valkey distributes monotonic policy revision invalidations through Valkey as advisory hints, not authorization or policy content.

Jump to

Keyboard shortcuts

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