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

authz

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package authz decides what an authenticated user may do: gates (named abilities) and policies (abilities on a model type). Decisions fail closed: an ability or policy that was never registered denies.

gate := authz.New(func(ctx context.Context) (*models.User, error) {
	u, err := auth.UserFrom[models.User](ctx, "web") // the session guard stores a value
	return &u, err
})
gate.Define("edit-settings", func(ctx context.Context, u *models.User) bool { return u.Role == "admin" })
gate.Register(authz.For[*models.Post](policies.PostPolicy{}))
r.Services().Authorizer = gate

if err := c.Authorize("update", post); err != nil { return err } // 403 / 404

See https://github.com/AlexGalhardo/vukem/blob/main/docs/authentication.md.

Example
package main

import (
	"context"
	"fmt"

	"github.com/AlexGalhardo/vukem/authz"
)

type exUser struct {
	ID    int
	Admin bool
}

type exPost struct{ AuthorID int }

type exPostPolicy struct{}

func (exPostPolicy) Update(_ context.Context, u *exUser, p *exPost) bool {
	return u.ID == p.AuthorID
}

func main() {
	// In an app the resolver reads auth.UserFrom[models.User](ctx, "web")
	// (the session guard stores the user by value) and returns &u.
	gate := authz.New(func(context.Context) (*exUser, error) { return &exUser{ID: 1}, nil })
	gate.Define("edit-settings", func(_ context.Context, u *exUser) bool { return u.Admin })
	if err := gate.Register(authz.For[*exPost](exPostPolicy{})); err != nil {
		fmt.Println(err)
		return
	}

	ctx := context.Background()
	alice := &exUser{ID: 1}
	fmt.Println(gate.Allows(ctx, alice, "update", &exPost{AuthorID: 1}))
	fmt.Println(gate.Allows(ctx, alice, "update", &exPost{AuthorID: 2}))
	fmt.Println(gate.Allows(ctx, alice, "edit-settings", nil))
	fmt.Println(gate.Allows(ctx, alice, "never-defined", nil))
}
Output:
true
false
false
false

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrForbidden = &errs.HTTPError{Status: http.StatusForbidden, Message: "This action is unauthorized."}

ErrForbidden is the default denial (403).

View Source
var ErrNoUser = &errs.HTTPError{Status: http.StatusUnauthorized, Message: "Unauthenticated."}

ErrNoUser is returned (401) when the user resolver finds nobody.

Functions

This section is empty.

Types

type Gate

type Gate[U any] struct {
	// contains filtered or unexported fields
}

Gate holds abilities and policies for users of type U.

func New

func New[U any](user func(ctx context.Context) (U, error)) *Gate[U]

New returns a gate; user resolves the current user from the request context (e.g. auth.UserFrom).

func (*Gate[U]) Allows

func (g *Gate[U]) Allows(ctx context.Context, u U, ability string, subject any) bool

Allows reports whether u may perform ability on subject.

func (*Gate[U]) Authorize

func (g *Gate[U]) Authorize(ctx context.Context, ability string, subject any) error

Authorize implements web.Authorizer: it resolves the current user from ctx and returns nil, ErrNoUser (401), a 403 or a 404. Unregistered abilities and policies deny (fail closed) and are reported in the returned error's cause for logs.

func (*Gate[U]) Before

func (g *Gate[U]) Before(fn func(ctx context.Context, u U, ability string) *Result)

Before runs before every check; a non-nil result decides (super-admins).

func (*Gate[U]) Check

func (g *Gate[U]) Check(ctx context.Context, u U, ability string, subject any) (Result, error)

Check decides ability for u on subject (nil for gate abilities).

func (*Gate[U]) Define

func (g *Gate[U]) Define(ability string, fn func(ctx context.Context, u U) bool)

Define registers a named ability.

func (*Gate[U]) DefineResult

func (g *Gate[U]) DefineResult(ability string, fn func(ctx context.Context, u U) Result)

DefineResult registers a named ability returning a Result (for 404s or custom messages).

func (*Gate[U]) Register

func (g *Gate[U]) Register(policies ...Policy) error

Register validates and adds policies. Signatures are checked here, at boot, so a typo fails fast instead of denying at runtime.

type Policy

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

Policy is a policy bound to a subject type, created by For.

func For

func For[T any](policy any) Policy

For binds policy to subject type T (usually a model pointer): ability "update" calls policy.Update(ctx, user, subject T) returning Result or bool. Methods without the subject parameter (Create(ctx, user)) serve type-level abilities: c.Authorize("create", (*models.Post)(nil)). A policy bound to *T also serves T values (a template ranging over []models.Post): the method receives a pointer to a copy.

type Result

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

Result is an authorization decision.

func Allow

func Allow() Result

Allow grants the ability.

func Deny

func Deny(message ...string) Result

Deny refuses with 403 and an optional message.

func DenyAsNotFound

func DenyAsNotFound() Result

DenyAsNotFound refuses with 404, hiding that the resource exists.

func (Result) Allowed

func (r Result) Allowed() bool

Allowed reports whether the result grants the ability.

Jump to

Keyboard shortcuts

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