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
- Variables
- func CollaboratorDefinitions(schema string) []string
- func IsOrgPermission(action Action) bool
- func IsResourcePermission(action Action) bool
- func ManagerRoleAllows(role string, action Action) bool
- func OrgRoleAllows(role string, action Action) bool
- func ResourceApp(resourceType string) string
- func ResourceRoleAllows(role string, action Action) bool
- func ResourceRoleFragment(resourceType string) string
- func ResourceRoleRank(role string) int
- func ResourceRoles() []string
- func ResourceRolesGranting(action Action) []string
- func ValidAppName(application string) bool
- func ValidResourceRole(role string) bool
- func ValidateAppSchema(app, schema string) error
- func ValidateResourceRef(ref ResourceRef) error
- func ValidateScope(app, scope string) error
- func ValidateVocabulary(v AppVocabulary) error
- type Action
- type AppRoleSyncer
- type AppVocabulary
- type Authorizer
- type Decision
- type DecisionAuthorizer
- type Engine
- type ErrorResponse
- type FeatureAuthorizer
- type Grant
- type ManagerRoleGetter
- type Middleware
- func (m *Middleware) RequireAction(resourceType ResourceType, action Action) func(http.Handler) http.Handler
- func (m *Middleware) RequireAllActions(resourceType ResourceType, actions ...Action) func(http.Handler) http.Handler
- func (m *Middleware) RequireAnyAction(resourceType ResourceType, actions ...Action) func(http.Handler) http.Handler
- func (m *Middleware) RequireResourceAction(extractor ResourceExtractor, action Action) func(http.Handler) http.Handler
- type Mode
- type ModeConfig
- type OrgAuthorizer
- type OrgMiddleware
- type PlatformAuthorizer
- type PlatformMiddleware
- type Principal
- type PrincipalType
- type Provider
- type RelationshipSyncer
- type Resource
- func NewOrgResource(resourceType ResourceType, orgID uuid.UUID) Resource
- func NewOwnedResource(resourceType ResourceType, id, ownerID uuid.UUID) Resource
- func NewPrincipalResource(id uuid.UUID) Resource
- func NewResource(resourceType ResourceType) Resource
- func NewResourceWithID(resourceType ResourceType, id uuid.UUID) Resource
- type ResourceExtractor
- type ResourceGrantReader
- type ResourceGrantSyncer
- type ResourceGranter
- type ResourceRef
- type ResourceSet
- type ResourceType
- type RoleHierarchy
- type RolePermissions
- type SpiceDBConfig
- type SyncMode
- type VocabularyRegistry
- func (r *VocabularyRegistry) AllScopes() []string
- func (r *VocabularyRegistry) Apps() []string
- func (r *VocabularyRegistry) CollaboratorResourceTypes(app string) []string
- func (r *VocabularyRegistry) ComposeSpiceDBSchema() (string, error)
- func (r *VocabularyRegistry) Get(app string) (AppVocabulary, bool)
- func (r *VocabularyRegistry) Register(v AppVocabulary) error
- func (r *VocabularyRegistry) ValidateResourceType(resourceType string) error
Constants ¶
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.
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.
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 ¶
var ( ErrMissingResourceID = &middlewareError{msg: "missing resource ID"} ErrInvalidResourceID = &middlewareError{msg: "invalid resource ID"} )
Error types for resource extraction.
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.
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).
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.
var ManagerRolePermissions = map[string][]Action{ ManagerRoleGuardian: {PermManageAccount, PermManageCredentials, PermViewProfile, PermManageManagers}, ManagerRoleEducator: {PermManageCredentials, PermViewProfile}, }
ManagerRolePermissions maps each built-in manager role to its platform permissions, mirroring the principal definition in BaseSpiceDBSchema.
var OrgRolePermissions = map[string][]Action{ "owner": { PermOrgManage, PermOrgEdit, PermOrgContribute, PermOrgView, PermOrgList, PermOrgInviteMember, PermOrgRemoveMember, PermOrgChangeRole, PermOrgSettings, PermOrgDelete, }, "admin": { PermOrgManage, PermOrgEdit, PermOrgContribute, PermOrgView, PermOrgList, PermOrgInviteMember, PermOrgRemoveMember, PermOrgChangeRole, PermOrgSettings, }, "member": {PermOrgContribute, PermOrgView, PermOrgList}, "collaborator": {PermOrgList}, }
OrgRolePermissions maps each organization role to its permissions, mirroring the organization definition in BaseSpiceDBSchema. A test keeps the two equal.
var ResourceRolePermissions = map[string][]Action{ ResourceRoleViewer: {PermResourceView}, ResourceRoleContributor: {PermResourceView, PermResourceEdit}, ResourceRoleMaintainer: {PermResourceView, PermResourceEdit, PermResourceManage}, }
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
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
IsOrgPermission reports whether action is a permission of the base organization definition.
func IsResourcePermission ¶ added in v0.14.0
IsResourcePermission reports whether action is one of the ladder's permissions.
func ManagerRoleAllows ¶ added in v0.14.0
ManagerRoleAllows reports whether a manager role grants a permission.
func OrgRoleAllows ¶ added in v0.14.0
OrgRoleAllows reports whether an organization role grants a permission of the base organization definition.
func ResourceApp ¶ added in v0.14.0
ResourceApp returns the application identifier of a resource type "{app}_{type}", or "" when it has none.
func ResourceRoleAllows ¶ added in v0.14.0
ResourceRoleAllows reports whether a resource role grants a permission.
func ResourceRoleFragment ¶ added in v0.14.0
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
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
ResourceRolesGranting returns the resource roles that grant action, lowest first.
func ValidAppName ¶ added in v0.14.0
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
ValidResourceRole reports whether role is a resource role.
func ValidateAppSchema ¶
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 ¶
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.
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.
type ErrorResponse ¶
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
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 ¶
NewServicePrincipal creates a Principal for a service.
func NewUserPrincipal ¶
NewUserPrincipal creates a Principal for a user.
func NewUserPrincipalWithAttrs ¶
NewUserPrincipalWithAttrs creates a Principal for a user with attributes.
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
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.
type ResourceExtractor ¶
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 ¶
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 ¶
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 ¶
func (r *VocabularyRegistry) Get(app string) (AppVocabulary, bool)
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.
Source Files
¶
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. |