Documentation
¶
Overview ¶
Package access is a permission vocabulary and the roles built from it: an app (or a plugin such as organization) declares which actions exist on which resources, defines roles as subsets of those statements, and asks a role whether it may do something.
It is the Go shape of better-auth's access plugin (createAccessControl, ac.newRole, role.authorize) and has no storage, no transport and no import of the auth core, so a role check costs a map lookup and the package can decide permissions for anything, not only organizations.
Why a role may only name declared statements ¶
A typo in a role definition ("membr": ["delete"]) must fail when the role is built, at start-up, rather than silently granting nothing until someone notices a button that never works, or, worse, granting something under a resource name an attacker can also spell. NewRole refuses any resource or action the AccessControl did not declare.
Example ¶
Example declares a vocabulary, builds two roles from it and checks them. ds:def id=example-gwg3tegh owner=@khanakia stability=stable
package main
import (
"errors"
"fmt"
"github.com/ubgo/auth/plugin/access"
)
func main() {
ac := access.MustNew(access.Statements{
"project": {"create", "share", "delete"},
"billing": {"read", "update"},
})
editor := ac.MustRole(access.Permissions{"project": {"create", "share"}})
accountant := ac.MustRole(access.Permissions{"billing": {"read", "update"}})
fmt.Println(editor.Allows(access.Request{"project": access.All("create", "share")}))
fmt.Println(editor.Authorize(access.Request{"project": access.Any("delete", "share")}, access.And) == nil)
err := accountant.Authorize(access.Request{"project": access.All("create")}, access.And)
fmt.Println(errors.Is(err, access.ErrDenied), err)
}
Output: true true true access: denied: You are not allowed to access resource: project
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnknownResource is a role, or a check, naming a resource the // statements do not declare. ErrUnknownResource = errors.New("access: unknown resource") // ErrUnknownAction is a role naming an action its resource does not // declare. ErrUnknownAction = errors.New("access: unknown action") // ErrEmptyStatements is an AccessControl with no resource, which no role // could grant anything from. ErrEmptyStatements = errors.New("access: no statements") // ErrDenied is a check the role does not pass; the returned error wraps // it with better-auth's message, which names the resource. ErrDenied = errors.New("access: denied") )
Errors.
Functions ¶
This section is empty.
Types ¶
type AccessControl ¶
type AccessControl struct {
// contains filtered or unexported fields
}
AccessControl holds the declared statements and builds roles from them. Build it with New; it is immutable afterwards and safe for concurrent use.
func MustNew ¶
func MustNew(s Statements) *AccessControl
MustNew is New for statements known at compile time; it panics on an error, which then shows at start-up.
func New ¶
func New(s Statements) (*AccessControl, error)
New declares the statements. Each resource needs at least one action and no action may repeat within a resource, so the vocabulary has one spelling for everything.
func (*AccessControl) Check ¶
func (ac *AccessControl) Check(p Permissions) error
Check reports whether p names only declared resources and actions: the validation NewRole applies, exported for a role stored at run time (the organization plugin's dynamic roles) before it is saved.
func (*AccessControl) MustRole ¶
func (ac *AccessControl) MustRole(p Permissions) Role
MustRole is NewRole for a role known at compile time; it panics on an error.
func (*AccessControl) NewRole ¶
func (ac *AccessControl) NewRole(p Permissions) (Role, error)
NewRole builds a role granting p, which must be a subset of the statements (Check).
func (*AccessControl) Statements ¶
func (ac *AccessControl) Statements() Statements
Statements returns a copy of the declared statements.
type Actions ¶
Actions is one resource's part of a Request: the actions asked for, and whether all of them (And, the default) or any one (Or) must be granted.
type Connector ¶
type Connector string
Connector says how several checks combine: every one must pass (And) or one is enough (Or).
type Permissions ¶
Permissions are a set of actions per resource, the same shape as Statements: what a role grants, or what a request asks for. JSON-encoded it is better-auth's permission object, so it is what an HTTP client sends.
func (Permissions) Clone ¶
func (p Permissions) Clone() Permissions
Clone returns a deep copy, so a caller can change it without touching a role's own map.
func (Permissions) Request ¶
func (p Permissions) Request() Request
Request turns p into a Request requiring every listed action.
type Request ¶
Request is a permission check: per resource, the actions asked for. Build one from Permissions with Permissions.Request when every action of every resource is required.
type Role ¶
type Role struct {
// contains filtered or unexported fields
}
Role is a set of granted actions per resource. The zero value grants nothing.
func (Role) Authorize ¶
Authorize checks req against the role; nil means allowed. connector joins the resources (And when empty): with And every resource must pass, with Or one is enough. A resource the role grants nothing on fails at once, whatever the connector, as in better-auth. An empty request is denied: asking for nothing proves nothing.
A denial wraps ErrDenied with better-auth's wording, so errors.Is works and the message matches what a better-auth client shows.
func (Role) Permissions ¶
func (r Role) Permissions() Permissions
Permissions returns a copy of what the role grants.
type Statements ¶
Statements are the resources of an application and the actions each one allows: {"project": ["create", "share", "delete"]}. The declared set is the whole vocabulary: a role can name nothing outside it.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package accessadmin decides plugin/admin's permissions with plugin/access roles: better-auth's admin `ac` and `roles` options.
|
Package accessadmin decides plugin/admin's permissions with plugin/access roles: better-auth's admin `ac` and `roles` options. |
|
Package accessapikey checks plugin/apikey's key permissions with a plugin/access access control, so the statements an app already declared for its roles are the vocabulary of its API keys too:
|
Package accessapikey checks plugin/apikey's key permissions with a plugin/access access control, so the statements an app already declared for its roles are the vocabulary of its API keys too: |