authz

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package authz provides a pluggable authorization interface for SystemForge applications.

The package defines a core Authorizer interface that applications use for access control, with two modes, named for the model they evaluate (ADR-008):

  • rbac (package authz/rbac): role-based. Organization roles, application roles and direct grants on resources, evaluated in process from the membership, role and grant tables. No external dependencies.
  • rebac (package authz/rebac/spicedb): relationship-based. Permissions derived through relationships by an engine, SpiceDB today (Zanzibar-style).

Both implement the same platform contract (Authorizer, OrgAuthorizer, PlatformAuthorizer and ResourceGranter, assembled as Provider) with the same semantics, verified by the authz/providertest suite. ModeConfig selects between them (the `authz` configuration key) and authz/mode builds the provider, so applications depend only on the interfaces and a deployment switches by configuration. The former paths authz/simple and authz/spicedb forward to the new packages and are deprecated.

Index

Constants

View Source
const (
	// ManagerRoleGuardian has full authority over a managed principal.
	ManagerRoleGuardian = "guardian"
	// ManagerRoleEducator has operational authority: credentials and
	// profile reads, without account or manager administration.
	ManagerRoleEducator = "educator"
)

Built-in manager roles (ADR-005). They are relations on principal in the base SpiceDB schema.

View Source
const (
	// ResourceRoleViewer reads the resource.
	ResourceRoleViewer = "viewer"
	// ResourceRoleContributor also changes the resource and creates items
	// within it.
	ResourceRoleContributor = "contributor"
	// ResourceRoleMaintainer also manages the resource's settings and its
	// collaborators.
	ResourceRoleMaintainer = "maintainer"
)

Resource roles are the standard ladder a resource type that accepts collaborators uses (ADR-008). Their names are reserved so that every application means the same thing by them; each role includes the ones below it. They are distinct from organization roles and from an application's own roles.

View Source
const BaseSpiceDBSchema = `` /* 1821-byte string literal not displayed */

BaseSpiceDBSchema is the SystemForge-owned foundation of every composed ReBAC deployment: principals, the organization membership ladder, and the platform. Applications never redefine these; they attach via an "{app}_org" facet definition that references organization and adds the app's domain roles (see docs/authz-conventions.md for the pattern and a worked example).

Variables

View Source
var (
	ErrMissingResourceID = &middlewareError{msg: "missing resource ID"}
	ErrInvalidResourceID = &middlewareError{msg: "invalid resource ID"}
)

Error types for resource extraction.

View Source
var (
	// ErrInvalidResourceRole means a role is not viewer, contributor or
	// maintainer.
	ErrInvalidResourceRole = errors.New("authz: invalid resource role")
	// ErrInvalidResource means a resource reference is malformed or names a
	// resource type that does not accept collaborators.
	ErrInvalidResource = errors.New("authz: invalid resource")
	// ErrGrantNotFound means the principal holds no grant on the resource.
	ErrGrantNotFound = errors.New("authz: resource grant not found")
	// ErrResourceOrganizationMismatch means the resource is already
	// granted in a different organization. A resource does not move
	// between organizations through a grant; the application moves its
	// grants with it.
	ErrResourceOrganizationMismatch = errors.New("authz: resource belongs to another organization")
)

Errors of the resource-grant operations.

View Source
var DefaultRoleHierarchy = RoleHierarchy{
	"owner":        100,
	"admin":        80,
	"member":       40,
	"collaborator": 20,
	"guest":        10,
}

DefaultRoleHierarchy provides the organization role hierarchy of the platform: owner, admin, member and collaborator (plus guest for applications that model one).

View Source
var DefaultRolePermissions = RolePermissions{
	"owner": {
		"org.delete", "org.manage", "org.settings",
		"member.invite", "member.remove", "member.role.change", "member.list",
		"resource.create", "resource.read", "resource.update", "resource.delete",
	},
	"admin": {
		"org.settings",
		"member.invite", "member.remove", "member.role.change", "member.list",
		"resource.create", "resource.read", "resource.update", "resource.delete",
	},
	"member": {
		"member.list",
		"resource.create", "resource.read", "resource.update",
	},

	"collaborator": {},
}

DefaultRolePermissions provides a common permission mapping.

ManagerRolePermissions maps each built-in manager role to its platform permissions, mirroring the principal definition in BaseSpiceDBSchema.

OrgRolePermissions maps each organization role to its permissions, mirroring the organization definition in BaseSpiceDBSchema. A test keeps the two equal.

ResourceRolePermissions maps each resource role to the permissions it grants on the resource, mirroring the relations of a collaborator-able resource definition (see ResourceRoleFragment). A test keeps the two equal.

Functions

func CollaboratorDefinitions added in v0.14.0

func CollaboratorDefinitions(schema string) []string

CollaboratorDefinitions returns the definitions of a schema fragment that accept collaborators: those declaring the whole resource-role ladder (viewer, contributor, maintainer).

func IsOrgPermission added in v0.14.0

func IsOrgPermission(action Action) bool

IsOrgPermission reports whether action is a permission of the base organization definition.

func IsResourcePermission added in v0.14.0

func IsResourcePermission(action Action) bool

IsResourcePermission reports whether action is one of the ladder's permissions.

func ManagerRoleAllows added in v0.14.0

func ManagerRoleAllows(role string, action Action) bool

ManagerRoleAllows reports whether a manager role grants a permission.

func OrgRoleAllows added in v0.14.0

func OrgRoleAllows(role string, action Action) bool

OrgRoleAllows reports whether an organization role grants a permission of the base organization definition.

func ResourceApp added in v0.14.0

func ResourceApp(resourceType string) string

ResourceApp returns the application identifier of a resource type "{app}_{type}", or "" when it has none.

func ResourceRoleAllows added in v0.14.0

func ResourceRoleAllows(role string, action Action) bool

ResourceRoleAllows reports whether a resource role grants a permission.

func ResourceRoleFragment added in v0.14.0

func ResourceRoleFragment(resourceType string) string

ResourceRoleFragment returns the standard SpiceDB definition of a resource type that accepts collaborators: the three ladder relations bound to principal, an org relation to the organization, and the view, edit and manage permissions. resourceType is "{app}_{type}".

func ResourceRoleRank added in v0.14.0

func ResourceRoleRank(role string) int

ResourceRoleRank orders the resource roles: viewer 1, contributor 2, maintainer 3, and 0 for anything else.

func ResourceRoles added in v0.14.0

func ResourceRoles() []string

ResourceRoles returns the resource roles, lowest first.

func ResourceRolesGranting added in v0.14.0

func ResourceRolesGranting(action Action) []string

ResourceRolesGranting returns the resource roles that grant action, lowest first.

func ValidAppName added in v0.14.0

func ValidAppName(application string) bool

ValidAppName reports whether application is a valid application identifier (lowercase letters and digits, 2 to 32 characters, starting with a letter), the form AppVocabulary.App must have.

func ValidResourceRole added in v0.14.0

func ValidResourceRole(role string) bool

ValidResourceRole reports whether role is a resource role.

func ValidateAppSchema

func ValidateAppSchema(app, schema string) error

ValidateAppSchema checks an app's SpiceDB fragment: every definition it declares must be prefixed "{app}_", so fragments can never collide with the shared base definitions or with another app, and a definition using the reserved resource-role names must declare the whole ladder (see validateCollaboratorDefinitions). An empty schema is valid.

func ValidateResourceRef added in v0.14.0

func ValidateResourceRef(ref ResourceRef) error

ValidateResourceRef checks the shape of a resource reference: a type of the form "{app}_{type}" with a valid application identifier, a non-empty identifier in the character set SpiceDB object identifiers allow (so both modes accept the same resources), and an organization.

func ValidateScope

func ValidateScope(app, scope string) error

ValidateScope checks one scope against the "{app}:{resource}:{verb}" (or "{app}:admin") convention for the given app.

func ValidateVocabulary

func ValidateVocabulary(v AppVocabulary) error

ValidateVocabulary checks a vocabulary against every convention: app name format, scope format and prefix, hierarchy covering all roles, and schema definition prefixing.

Types

type Action

type Action string

Action represents an operation being performed.

const (
	// PermManageAccount covers consent, deletion, and billing.
	PermManageAccount Action = "manage_account"
	// PermManageCredentials covers issuing and revoking sign-in
	// credentials and sessions.
	PermManageCredentials Action = "manage_credentials" //nolint:gosec // G101: a permission name, not a credential
	// PermViewProfile covers reading the principal's profile.
	PermViewProfile Action = "view_profile"
	// PermManageManagers covers adding and removing other managers.
	PermManageManagers Action = "manage_managers"
)

Platform permissions a manager holds over a principal.

const (
	PermOrgManage       Action = "manage"
	PermOrgEdit         Action = "edit"
	PermOrgContribute   Action = "contribute"
	PermOrgView         Action = "view"
	PermOrgList         Action = "list"
	PermOrgInviteMember Action = "invite_member"
	PermOrgRemoveMember Action = "remove_member"
	PermOrgChangeRole   Action = "change_role"
	PermOrgSettings     Action = "settings"
	PermOrgDelete       Action = "delete"
)

Organization permissions of the base SpiceDB schema: the membership ladder and organization administration. Check them with NewResourceWithID(ResourceTypeOrganization, orgID); both providers evaluate them the same way.

const (
	PermResourceView   Action = "view"
	PermResourceEdit   Action = "edit"
	PermResourceManage Action = "manage"
)

Resource permissions of the ladder. A resource definition exposes them under these names, and both providers answer them: Can(principal, PermResourceView, resource), and ListResources with one of them.

const (
	ActionCreate Action = "create"
	ActionRead   Action = "read"
	ActionUpdate Action = "update"
	ActionDelete Action = "delete"
	ActionList   Action = "list"
	ActionManage Action = "manage" // Full CRUD + admin operations
)

Common action constants.

type AppRoleSyncer added in v0.14.0

type AppRoleSyncer interface {
	// AddAppRole records that the principal holds role in application for
	// the organization. Called when an application role is assigned or
	// changed.
	AddAppRole(ctx context.Context, principalID, orgID uuid.UUID, application, role string) error

	// RemoveAppRole removes the principal's role in application for the
	// organization. Called when an application role is removed or changed.
	RemoveAppRole(ctx context.Context, principalID, orgID uuid.UUID, application, role string) error
}

AppRoleSyncer is implemented by a RelationshipSyncer that also writes application roles (ADR-007) to the authorization graph. It is a separate interface so existing RelationshipSyncer implementers keep compiling; callers type-assert a syncer to it and skip application roles when it does not implement it. The relationship-based provider writes "{application}_org:{org}#{role}@principal:{principal}", the facet an application's schema fragment attaches to the base organization.

type AppVocabulary

type AppVocabulary interface {
	// App returns the application identifier (e.g. "actionforge").
	App() string
	// Roles maps each role name to its granted dotted permissions.
	Roles() RolePermissions
	// Hierarchy orders the app's roles; every role in Roles() must appear.
	Hierarchy() RoleHierarchy
	// Scopes lists every OAuth scope the app defines.
	Scopes() []string
	// SpiceDBSchema returns the app's ReBAC schema fragment, or "" if the app
	// only supports the role-based (rbac) provider.
	SpiceDBSchema() string
}

AppVocabulary is the authorization vocabulary a Forge application registers with the platform: its roles, permissions, OAuth scopes, and (optionally) its SpiceDB schema fragment. Registering a vocabulary is what makes an app administrable — the IAM console renders roles/permissions/scopes directly from the registry, and the composed SpiceDB schema is assembled from the registered fragments.

Conventions (normative; see docs/authz-conventions.md):

  • App names are short lowercase identifiers ("actionforge").
  • Scopes are "{app}:{resource}:{verb}" plus the blanket "{app}:admin".
  • Application roles are the application's own (for example "viewer", "editor", "approver") and must appear in both Roles() and Hierarchy(). They are distinct from organization roles (owner, admin, member, collaborator) and from resource roles (viewer, contributor, maintainer on a resource).
  • SpiceDB fragments define only "{app}_"-prefixed definitions and attach to the shared base definitions (principal, organization, platform) via an "{app}_org" facet — never by redefining the base.

type Authorizer

type Authorizer interface {
	// Can checks if a principal can perform an action on a resource.
	// This is the primary authorization method.
	Can(ctx context.Context, principal Principal, action Action, resource Resource) (bool, error)

	// CanAll checks if a principal can perform all specified actions on a resource.
	CanAll(ctx context.Context, principal Principal, actions []Action, resource Resource) (bool, error)

	// CanAny checks if a principal can perform any of the specified actions on a resource.
	CanAny(ctx context.Context, principal Principal, actions []Action, resource Resource) (bool, error)

	// Filter returns only the resources the principal can access with the given action.
	Filter(ctx context.Context, principal Principal, action Action, resources []Resource) ([]Resource, error)
}

Authorizer defines the core authorization interface. All authorization backends must implement this interface.

type Decision

type Decision struct {
	// Allowed indicates whether the action is permitted.
	Allowed bool

	// Reason provides context for the decision (useful for debugging/auditing).
	Reason string

	// PolicyID identifies which policy made the decision (if applicable).
	PolicyID string
}

Decision represents an authorization decision with optional explanation.

type DecisionAuthorizer

type DecisionAuthorizer interface {
	Authorizer

	// Decide returns a detailed authorization decision.
	Decide(ctx context.Context, principal Principal, action Action, resource Resource) (Decision, error)
}

DecisionAuthorizer provides detailed authorization decisions.

type Engine added in v0.14.0

type Engine string

Engine names the relationship engine behind ModeReBAC.

const EngineSpiceDB Engine = "spicedb"

EngineSpiceDB is the SpiceDB engine, package authz/rebac/spicedb. It is the only engine today; another, such as OpenFGA, would sit beside it without changing this configuration's vocabulary.

func Engines added in v0.14.0

func Engines() []Engine

Engines returns the relationship engines this version supports.

type ErrorResponse

type ErrorResponse struct {
	Error   string `json:"error"`
	Message string `json:"message,omitempty"`
}

ErrorResponse represents an error response body.

type FeatureAuthorizer

type FeatureAuthorizer interface {
	Authorizer

	// CanWithFeature checks both permission and feature flag.
	CanWithFeature(ctx context.Context, principal Principal, action Action, resource Resource, feature string) (bool, error)
}

FeatureAuthorizer extends authorization with feature flag awareness.

type Grant added in v0.14.0

type Grant struct {
	PrincipalID uuid.UUID
	Resource    ResourceRef
	// Role is a resource role.
	Role string
	// GrantedBy is the principal who made the grant, when known.
	GrantedBy *uuid.UUID
}

Grant is a principal's role on one resource.

type ManagerRoleGetter added in v0.14.0

type ManagerRoleGetter func(ctx context.Context, managerID, managedID uuid.UUID) ([]string, error)

ManagerRoleGetter returns the active manager roles managerID holds over managedID, or none.

type Middleware

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

Middleware wraps an Authorizer for HTTP middleware use.

func NewMiddleware

func NewMiddleware(authorizer Authorizer) *Middleware

NewMiddleware creates a new authorization middleware.

func (*Middleware) RequireAction

func (m *Middleware) RequireAction(resourceType ResourceType, action Action) func(http.Handler) http.Handler

RequireAction returns middleware that checks if the user can perform an action on a resource type.

func (*Middleware) RequireAllActions

func (m *Middleware) RequireAllActions(resourceType ResourceType, actions ...Action) func(http.Handler) http.Handler

RequireAllActions returns middleware that checks if the user can perform all of the specified actions on a resource type.

func (*Middleware) RequireAnyAction

func (m *Middleware) RequireAnyAction(resourceType ResourceType, actions ...Action) func(http.Handler) http.Handler

RequireAnyAction returns middleware that checks if the user can perform any of the specified actions on a resource type.

func (*Middleware) RequireResourceAction

func (m *Middleware) RequireResourceAction(extractor ResourceExtractor, action Action) func(http.Handler) http.Handler

RequireResourceAction returns middleware that extracts a resource from the request and checks if the user can perform an action on it.

type Mode added in v0.14.0

type Mode string

Mode names how a deployment evaluates authorization (ADR-008). The modes are named for the model they evaluate, not the technology.

const (
	// ModeRBAC is role-based: organization roles, application roles and
	// direct grants on resources, evaluated in process from the membership,
	// role and grant tables (package authz/rbac).
	ModeRBAC Mode = "rbac"

	// ModeReBAC is relationship-based: permissions derived through
	// relationships by an engine, which Engine selects (package
	// authz/rebac/<engine>).
	ModeReBAC Mode = "rebac"
)

type ModeConfig added in v0.14.0

type ModeConfig struct {
	// Mode is "rbac" (the default) or "rebac".
	Mode Mode `` /* 201-byte string literal not displayed */

	// Engine selects the relationship engine for mode rebac; default
	// "spicedb". It must be empty for mode rbac.
	Engine Engine `` /* 138-byte string literal not displayed */

	// SpiceDB configures the spicedb engine. Nil means an embedded
	// in-memory instance, for development and tests.
	SpiceDB *SpiceDBConfig `json:"spicedb,omitempty" yaml:"spicedb,omitempty" jsonschema:"description=SpiceDB engine settings for mode rebac"`
}

ModeConfig is the authorization configuration of a deployment: the `authz` key of the SystemAuth configuration file.

authz:
  mode: rebac
  engine: spicedb
  spicedb:
    mode: remote
    endpoint: spicedb.internal:50051
    token: ${SPICEDB_TOKEN}

ModeConfig only describes the choice. authz/mode.New builds the provider from it, because the providers import this package.

func (*ModeConfig) ApplyDefaults added in v0.14.0

func (c *ModeConfig) ApplyDefaults()

ApplyDefaults fills in the defaults: mode rbac; for rebac, engine spicedb with an embedded in-memory instance.

func (ModeConfig) Validate added in v0.14.0

func (c ModeConfig) Validate() error

Validate checks the configuration, after ApplyDefaults. The errors name the key and the accepted values.

type OrgAuthorizer

type OrgAuthorizer interface {
	Authorizer

	// CanForOrg checks permission scoped to a specific organization.
	CanForOrg(ctx context.Context, principal Principal, orgID uuid.UUID, action Action, resource Resource) (bool, error)

	// GetRole returns the principal's role in an organization.
	GetRole(ctx context.Context, principal Principal, orgID uuid.UUID) (string, error)

	// IsMember checks if a principal is a member of an organization.
	IsMember(ctx context.Context, principal Principal, orgID uuid.UUID) (bool, error)
}

OrgAuthorizer extends Authorizer with organization-scoped methods. Use this for multi-tenant SaaS applications.

type OrgMiddleware

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

OrgMiddleware wraps an OrgAuthorizer for organization-scoped middleware.

func NewOrgMiddleware

func NewOrgMiddleware(authorizer OrgAuthorizer) *OrgMiddleware

NewOrgMiddleware creates a new organization-scoped authorization middleware.

func (*OrgMiddleware) RequireMembership

func (m *OrgMiddleware) RequireMembership() func(http.Handler) http.Handler

RequireMembership returns middleware that requires the user to be a member of the current organization.

func (*OrgMiddleware) RequireRole

func (m *OrgMiddleware) RequireRole(role string, hierarchy RoleHierarchy) func(http.Handler) http.Handler

RequireRole returns middleware that requires a specific role in the current organization.

type PlatformAuthorizer

type PlatformAuthorizer interface {
	OrgAuthorizer

	// IsPlatformAdmin checks if a principal has platform-wide admin access.
	IsPlatformAdmin(ctx context.Context, principal Principal) (bool, error)
}

PlatformAuthorizer extends OrgAuthorizer with platform-level checks.

type PlatformMiddleware

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

PlatformMiddleware wraps a PlatformAuthorizer for platform-level middleware.

func NewPlatformMiddleware

func NewPlatformMiddleware(authorizer PlatformAuthorizer) *PlatformMiddleware

NewPlatformMiddleware creates a new platform-level authorization middleware.

func (*PlatformMiddleware) RequirePlatformAdmin

func (m *PlatformMiddleware) RequirePlatformAdmin() func(http.Handler) http.Handler

RequirePlatformAdmin returns middleware that requires platform admin status.

type Principal

type Principal struct {
	// ID is the unique identifier of the principal.
	ID uuid.UUID

	// Type identifies the kind of principal (user, service, api_key, etc.).
	Type PrincipalType

	// Attributes contains additional principal attributes for ABAC.
	Attributes map[string]any
}

Principal represents an entity requesting access (user, service, etc.).

func NewServicePrincipal

func NewServicePrincipal(serviceID uuid.UUID) Principal

NewServicePrincipal creates a Principal for a service.

func NewUserPrincipal

func NewUserPrincipal(userID uuid.UUID) Principal

NewUserPrincipal creates a Principal for a user.

func NewUserPrincipalWithAttrs

func NewUserPrincipalWithAttrs(userID uuid.UUID, attrs map[string]any) Principal

NewUserPrincipalWithAttrs creates a Principal for a user with attributes.

func (Principal) WithAttr

func (p Principal) WithAttr(key string, value any) Principal

WithAttr returns a copy of the Principal with an additional attribute.

type PrincipalType

type PrincipalType string

PrincipalType identifies the kind of principal.

const (
	PrincipalTypeUser    PrincipalType = "user"
	PrincipalTypeService PrincipalType = "service"
	PrincipalTypeAPIKey  PrincipalType = "api_key"
	PrincipalTypeSystem  PrincipalType = "system"
)

type Provider added in v0.14.0

type Provider interface {
	PlatformAuthorizer
	ResourceGranter
}

Provider is what a configured mode provides, whichever mode it is: the platform authorizer and the resource-grant contract. The role-based provider also implements DecisionAuthorizer; assert for it when a reason is wanted.

type RelationshipSyncer

type RelationshipSyncer interface {
	// AddOrgMembership registers a principal's membership in an organization with a specific role.
	// Called when a user joins an organization or is invited.
	AddOrgMembership(ctx context.Context, principalID, orgID uuid.UUID, role string) error

	// RemoveOrgMembership removes a principal's membership from an organization.
	// Called when a user leaves or is removed from an organization.
	RemoveOrgMembership(ctx context.Context, principalID, orgID uuid.UUID, role string) error

	// UpdateOrgMembership changes a principal's role in an organization.
	// Implemented as remove old role + add new role atomically.
	UpdateOrgMembership(ctx context.Context, principalID, orgID uuid.UUID, oldRole, newRole string) error

	// RegisterPrincipal creates a principal entity in the authorization system.
	// Called when a new user, application, agent, or service principal is created.
	RegisterPrincipal(ctx context.Context, principalID uuid.UUID) error

	// UnregisterPrincipal removes a principal and all its relationships from the authorization system.
	// Called when a principal is deleted.
	UnregisterPrincipal(ctx context.Context, principalID uuid.UUID) error

	// RegisterOrganization creates an organization in the authorization system with an initial owner.
	// Called when a new organization is created.
	RegisterOrganization(ctx context.Context, orgID, ownerID uuid.UUID) error

	// UnregisterOrganization removes an organization and all its relationships from the authorization system.
	// Called when an organization is deleted.
	UnregisterOrganization(ctx context.Context, orgID uuid.UUID) error

	// SetPlatformAdmin grants or revokes platform admin privileges for a principal.
	SetPlatformAdmin(ctx context.Context, principalID uuid.UUID, isAdmin bool) error

	// AddPrincipalManager records that managerID manages managedID with a
	// manager role such as guardian or educator (ADR-005).
	AddPrincipalManager(ctx context.Context, managedID, managerID uuid.UUID, role string) error

	// RemovePrincipalManager removes a manager relation.
	RemovePrincipalManager(ctx context.Context, managedID, managerID uuid.UUID, role string) error
}

RelationshipSyncer defines the interface for syncing identity changes to an authorization backend. Identity services use this interface to keep the authorization layer in sync with membership and principal lifecycle events.

type Resource

type Resource struct {
	// Type identifies the kind of resource (course, organization, etc.).
	Type ResourceType

	// ID is the unique identifier of the resource (nil for type-level checks).
	ID *uuid.UUID

	// OwnerID is the owner of the resource (for ownership-based access).
	OwnerID *uuid.UUID

	// OrgID is the organization this resource belongs to.
	OrgID *uuid.UUID

	// Attributes contains additional resource attributes for ABAC.
	Attributes map[string]any
}

Resource represents something being accessed.

func NewOrgResource

func NewOrgResource(resourceType ResourceType, orgID uuid.UUID) Resource

NewOrgResource creates a Resource scoped to an organization.

func NewOwnedResource

func NewOwnedResource(resourceType ResourceType, id, ownerID uuid.UUID) Resource

NewOwnedResource creates a Resource with an owner.

func NewPrincipalResource added in v0.14.0

func NewPrincipalResource(id uuid.UUID) Resource

NewPrincipalResource returns the resource for permissions over a principal.

func NewResource

func NewResource(resourceType ResourceType) Resource

NewResource creates a Resource with the given type.

func NewResourceWithID

func NewResourceWithID(resourceType ResourceType, id uuid.UUID) Resource

NewResourceWithID creates a Resource with type and ID.

func (Resource) IsOwner

func (r Resource) IsOwner(principalID uuid.UUID) bool

IsOwner checks if the principal owns this resource.

func (Resource) WithAttr

func (r Resource) WithAttr(key string, value any) Resource

WithAttr returns a copy of the Resource with an additional attribute.

func (Resource) WithOrg

func (r Resource) WithOrg(orgID uuid.UUID) Resource

WithOrg returns a copy of the Resource with the specified organization.

func (Resource) WithOwner

func (r Resource) WithOwner(ownerID uuid.UUID) Resource

WithOwner returns a copy of the Resource with the specified owner.

type ResourceExtractor

type ResourceExtractor func(r *http.Request) (Resource, error)

ResourceExtractor is a function that extracts a resource from an HTTP request. Use this for routes that include resource IDs in the path.

func WithResourceID

func WithResourceID(resourceType ResourceType, pathParamName string, getParam func(r *http.Request, key string) string) ResourceExtractor

WithResourceID creates a ResourceExtractor that parses a resource ID from a URL path parameter.

type ResourceGrantReader added in v0.14.0

type ResourceGrantReader interface {
	// ResourceRole returns the resource role the principal holds on the
	// resource through an active membership, or "".
	ResourceRole(ctx context.Context, principalID uuid.UUID, resource ResourceRef) (string, error)

	// OrganizationRoles returns the principal's role in each organization
	// where it has an active membership.
	OrganizationRoles(ctx context.Context, principalID uuid.UUID) (map[uuid.UUID]string, error)
}

ResourceGrantReader is what the role-based provider reads at check time. The Ent-backed grant service implements it next to ResourceGranter.

type ResourceGrantSyncer added in v0.14.0

type ResourceGrantSyncer interface {
	// SetResourceGrant records that the principal holds role on the
	// resource, replacing any other role it held there in one write.
	SetResourceGrant(ctx context.Context, principalID uuid.UUID, resource ResourceRef, role string) error

	// RemoveResourceGrant removes every role the principal holds on the
	// resource.
	RemoveResourceGrant(ctx context.Context, principalID uuid.UUID, resource ResourceRef) error
}

ResourceGrantSyncer is implemented by a RelationshipSyncer that also writes resource grants to the authorization graph. Like AppRoleSyncer it is a separate interface so existing syncers keep compiling; callers type-assert and skip grants when it is not implemented.

type ResourceGranter added in v0.14.0

type ResourceGranter interface {
	// GrantResourceRole gives the principal a role on the resource,
	// replacing any role it held there. grantedBy is the principal making
	// the grant; the zero UUID records none.
	GrantResourceRole(ctx context.Context, principalID uuid.UUID, resource ResourceRef, role string, grantedBy uuid.UUID) error

	// RevokeResourceRole removes the principal's grant on the resource.
	// It returns ErrGrantNotFound when there is none.
	RevokeResourceRole(ctx context.Context, principalID uuid.UUID, resource ResourceRef) error

	// ListResourceGrants lists the grants on one resource, highest role
	// first.
	ListResourceGrants(ctx context.Context, resource ResourceRef) ([]Grant, error)

	// ListResources returns the resources of resourceType on which the
	// principal holds permission (view, edit or manage). An application
	// uses the result to constrain queries and row-level security, in
	// addition to checking each request.
	ListResources(ctx context.Context, principalID uuid.UUID, resourceType string, permission Action) (ResourceSet, error)
}

ResourceGranter is the grant half of the platform contract (ADR-008), implemented with the same semantics by the role-based and the relationship-based providers and checked by the providertest suite.

Granting to a principal with no membership in the resource's organization adds a collaborator membership; revoking the last grant of a collaborator removes it. A grant to a lower role than the principal held, and a revoke, record an access change.

type ResourceRef added in v0.14.0

type ResourceRef struct {
	// Type is the definition name, "{app}_{type}", as declared in the
	// application's vocabulary.
	Type string
	// ID is the application's identifier of the resource.
	ID string
	// OrganizationID is the organization that owns the resource. Reads may
	// leave it zero to mean the organization the grant was made in.
	OrganizationID uuid.UUID
}

ResourceRef identifies one resource of an organization. The identifier is the application's own string, so the substrate stores grants for resources it knows nothing else about.

func ResourceRefOf added in v0.14.0

func ResourceRefOf(r Resource) (ResourceRef, bool)

ResourceRefOf returns the reference for a Resource with an ID. The organization is Resource.OrgID when set.

type ResourceSet added in v0.14.0

type ResourceSet struct {
	// IDs are resources the principal holds the permission on directly,
	// through a grant, or, in the relationship-based mode, through any
	// relationship the schema expresses.
	IDs []string
	// OrganizationIDs are organizations in which the principal's
	// organization role grants the permission on every resource of the
	// type. The relationship-based provider leaves it empty: its lookup
	// already returns each resource in IDs.
	OrganizationIDs []uuid.UUID
}

ResourceSet is the answer to ListResources: the resources a principal holds a permission on, in two parts so that an application can apply them as `org_id IN (OrganizationIDs) OR id IN (IDs)`.

type ResourceType

type ResourceType string

ResourceType identifies the kind of resource.

const (
	ResourceTypeOrganization ResourceType = "organization"
	ResourceTypeMember       ResourceType = "member"
	ResourceTypeUser         ResourceType = "user"
)

Common resource type constants.

const ResourceTypePrincipal ResourceType = "principal"

ResourceTypePrincipal is the resource type for permissions one principal holds over another, such as a manager over a managed principal.

type RoleHierarchy

type RoleHierarchy map[string]int

RoleHierarchy defines a hierarchy of roles where higher values indicate more access. Roles with higher hierarchy values can access resources requiring lower levels.

func (RoleHierarchy) CanAccess

func (h RoleHierarchy) CanAccess(userRole, requiredRole string) bool

CanAccess checks if a user role can access resources requiring the target role. Higher hierarchy values can access lower ones.

func (RoleHierarchy) IsHigherOrEqual

func (h RoleHierarchy) IsHigherOrEqual(role1, role2 string) bool

IsHigherOrEqual checks if role1 is higher than or equal to role2.

func (RoleHierarchy) Level

func (h RoleHierarchy) Level(role string) int

Level returns the hierarchy level for a role, or 0 if not found.

type RolePermissions

type RolePermissions map[string][]string

RolePermissions maps roles to their granted permissions.

func (RolePermissions) GetPermissions

func (rp RolePermissions) GetPermissions(role string) []string

GetPermissions returns all permissions for a role.

func (RolePermissions) HasAllPermissions

func (rp RolePermissions) HasAllPermissions(role string, permissions []string) bool

HasAllPermissions checks if a role has all of the specified permissions.

func (RolePermissions) HasAnyPermission

func (rp RolePermissions) HasAnyPermission(role string, permissions []string) bool

HasAnyPermission checks if a role has any of the specified permissions.

func (RolePermissions) HasPermission

func (rp RolePermissions) HasPermission(role, permission string) bool

HasPermission checks if a role has a specific permission.

type SpiceDBConfig added in v0.14.0

type SpiceDBConfig struct {
	// Mode is how SpiceDB runs: "embedded" (in this process, the default)
	// or "remote" (a service reached over gRPC).
	Mode string `` /* 158-byte string literal not displayed */

	// DatastoreEngine is the embedded datastore: "memory" (default) or
	// "postgres".
	DatastoreEngine string `` /* 152-byte string literal not displayed */

	// DatastoreURI is the connection string of the embedded postgres
	// datastore.
	DatastoreURI string `` /* 168-byte string literal not displayed */

	// Endpoint is the gRPC address of a remote SpiceDB, "host:port".
	Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty" jsonschema:"description=gRPC address of a remote SpiceDB"`

	// Token is the preshared key of a remote SpiceDB.
	Token string `` //nolint:gosec // G117: a configured credential, injected from the environment
	/* 133-byte string literal not displayed */

	// Insecure skips TLS to a remote SpiceDB. Development only.
	Insecure bool `` /* 148-byte string literal not displayed */

	// WriteSchema writes the composed schema (the base schema and every
	// registered vocabulary's fragment) to the engine at startup. An
	// embedded instance always gets it, since it starts empty; for a remote
	// one it is off by default, because a shared service's schema is an
	// operational decision.
	WriteSchema bool `` /* 155-byte string literal not displayed */
}

SpiceDBConfig holds the settings of the SpiceDB engine. It is the configuration type of authz/rebac/spicedb (spicedb.Config is an alias), declared here so that loading configuration does not pull the SpiceDB server into every importer of this package.

type SyncMode

type SyncMode string

SyncMode determines how sync failures are handled.

const (
	// SyncModeStrict fails the operation if authorization sync fails.
	// Use when authorization must be consistent with identity.
	SyncModeStrict SyncMode = "strict"

	// SyncModeEventual logs sync failures but allows the operation to succeed.
	// Use when eventual consistency is acceptable and a retry mechanism exists.
	SyncModeEventual SyncMode = "eventual"
)

type VocabularyRegistry

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

VocabularyRegistry holds the vocabularies of every app in a deployment. A composed deployment registers each Forge app at startup; registration validates the vocabulary so convention drift fails fast rather than surfacing as authorization bugs.

func NewVocabularyRegistry

func NewVocabularyRegistry() *VocabularyRegistry

NewVocabularyRegistry returns an empty registry.

func (*VocabularyRegistry) AllScopes

func (r *VocabularyRegistry) AllScopes() []string

AllScopes returns every registered scope, sorted, for consent screens and principal AllowedScopes configuration.

func (*VocabularyRegistry) Apps

func (r *VocabularyRegistry) Apps() []string

Apps returns the registered app names in registration order.

func (*VocabularyRegistry) CollaboratorResourceTypes added in v0.14.0

func (r *VocabularyRegistry) CollaboratorResourceTypes(app string) []string

CollaboratorResourceTypes returns the resource types of an application that accept collaborators according to its SpiceDB fragment, sorted. It is empty for an unregistered application or one with no fragment.

func (*VocabularyRegistry) ComposeSpiceDBSchema

func (r *VocabularyRegistry) ComposeSpiceDBSchema() (string, error)

ComposeSpiceDBSchema assembles the deployment's full SpiceDB schema: the SystemForge base followed by every registered app's fragment in registration order. It fails on any duplicate definition — impossible when fragments follow the "{app}_" prefix convention, but verified anyway so a bad fragment cannot silently shadow another app's (or the base's) definitions.

func (*VocabularyRegistry) Get

Get returns the vocabulary registered for app.

func (*VocabularyRegistry) Register

func (r *VocabularyRegistry) Register(v AppVocabulary) error

Register validates and adds an app's vocabulary. Registering the same app twice is an error.

func (*VocabularyRegistry) ValidateResourceType added in v0.14.0

func (r *VocabularyRegistry) ValidateResourceType(resourceType string) error

ValidateResourceType checks that resourceType may be granted on: its "{app}_" prefix names a vocabulary in the registry, and, when that vocabulary carries a SpiceDB fragment, the fragment declares the type with the whole resource-role ladder (CollaboratorDefinitions). A vocabulary with no fragment supports only the role-based provider, where any type of the application can be granted on.

Directories

Path Synopsis
Package mode builds the authorization provider a deployment configured (ADR-008): role-based ("rbac") or relationship-based ("rebac") with an engine, from an authz.ModeConfig.
Package mode builds the authorization provider a deployment configured (ADR-008): role-based ("rbac") or relationship-based ("rebac") with an engine, from an authz.ModeConfig.
Package noop provides a no-operation authorization syncer for deployments that don't require authorization backend synchronization.
Package noop provides a no-operation authorization syncer for deployments that don't require authorization backend synchronization.
Package providertest provides conformance tests for authz.Provider implementations.
Package providertest provides conformance tests for authz.Provider implementations.
Package rbac provides the role-based authorization provider, the "rbac" mode of ADR-008.
Package rbac provides the role-based authorization provider, the "rbac" mode of ADR-008.
rebac
spicedb
Package spicedb provides SpiceDB-based authorization for SystemForge.
Package spicedb provides SpiceDB-based authorization for SystemForge.
Package simple is the former import path of the role-based authorization provider.
Package simple is the former import path of the role-based authorization provider.
Package spicedb is the former import path of the SpiceDB engine for relationship-based authorization.
Package spicedb is the former import path of the SpiceDB engine for relationship-based authorization.

Jump to

Keyboard shortcuts

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