# Authorization made most simple

One of the things I often struggle with in my go applications is authorization. Lots of the tools out there are complex or made for use-cases much larger than my own. In a recent project I came up with a very simple approach.

**TLDR;** Checkout a generic form here: [https://github.com/ryanfaerman/can](https://github.com/ryanfaerman/can)

I'll show you what I came up with first and then, a slightly more generic version.

Let's define a couple interfaces and a model:

```go

// Canner allows a resource to define if an account can perform 
// a given action.
type Canner interface {
	Can(account *Account, action string) error
}

// Verber is used to allow a resource to define the actions 
// it supports.
type Verber interface {
	Verbs() []string
}

type Account {
    ID        int
    Name      string
    Anonymous bool
    // ... use your actual model
}

var AnonymousAccount = Account{ID: -1, Name: "Anon", Anonymous: true}
```

And while we're at it, a basic container type:

```go
// Policy is a map of actions to functions that
// return an error if the action cannot be performed for the 
// given account.
type Policy map[string]func(*Account) error

// Verbs implements the Verber interface.
func (p Policy) Verbs() []string {
	var verbs []string
	for verb := range p {
		verbs = append(verbs, verb)
	}
	return verbs
}

// Can implements the Canner interface.
func (p Policy) Can(account *Account, action string) error {
	if fn, ok := p[action]; ok {
		return fn(account)
	}
	return nil
}

// An example default policy.
var DefaultPolicy = Policy{
    // Anonymous users aren't allowed to view anything
    "view": func(account *Account) error {
        if account.Anonymous {
            return errors.New("must not be anonymous")
        }
    },
    
    // Editing is disabled for everyone
    "edit": func(account *Account) error {
        return errors.New("editing is forbidden")
    },
}
```

And, let's also create an example subject that we want to act on:

```go
type BlogPost struct {
    Title string
    Body  string
    Owner *Account
}

func (b *BlogPost) Verbs() []string {
    return []string{"view", "edit", "promote", "delete"}
}

func (b *BlogPost) Can(account *Account, action string) error {
    switch action {
        case "view":
            // anyone can view
            return nil
        case "edit"
            if b.Owner.ID != account.ID {
                return errors.New("cannot edit someone elses blogpost")
            }
            return nil
        // case ...
    }
    return nil
}
```

Now with those few things, we can build out the actual function that makes this idea work:

```go
func Can(account *Account, action string, resources ...any) error {
	if account == nil {
		account = AnonymousAccount
	}
	if len(resources) == 0 {
		resources = append(resources, DefaultPolicy)
	}

	for _, resource := range resources {
		if r, ok := resource.(Verber); ok {
			if !slices.Contains(r.Verbs(), action) {
				return ErrInvalidAction
			}
		}

		if r, ok := resource.(Canner); ok {
			if err := r.Can(account, action); err != nil {
				return errors.Join(ErrNotAuthorized, err)
			}
		}
	}

	return nil
}

// Some sugar!
func Cannot(account *Account, action string, resources ...any) error {
    !Can(account, action, resources...)
}
```

Now, scattered in our codebase we can do things like:

```go
// ..
b := LoadBlogPost()
if Cannot(someAccount, "edit", b) {
    //... do something
}
```

Granted, this is partially contrived. In my application I'm using an actual model, not just a random struct, but most of it is pretty similar to what I have.

Two more fun things before we wrap this up.

If you're using templ, like I am, I made a couple helpers.

```go
func CurrentAccount(ctx context.Context) *models.Account {
	// Get the current user from the account
    // Or return an AnonymousUser
}

func UserCan(ctx context.Context, action string, resources ...any) bool {
	if err := services.Authorization.Can(CurrentAccount(ctx), action, resources...); err != nil {
		return false
	}
	return true
}

templ Can(action string, resources ...any) {
	if UserCan(ctx, action, resources...) {
		{ children... }
	}
}

templ Cannot(action string, resources ...any) {
	if !UserCan(ctx, action, resources...) {
		{ children... }
	}
}

// in some templ file:

@Can("edit", theBlogPost) {
    <h1>You can Edit this!</h1>
}
@Cannot("edit", theBlogPost) {
    <h1>Sorry bud! You cannot do that</h1>
}
```

I've split up the `UserCan` from `Can` and `Cannot` because doing assignments and error checking is a bit of a pain in templ.

If you want to see this in a less of a contrived fashion, you can view it in action in my application: [https://github.com/ryanfaerman/netctl/blob/master/internal/services/authorization.go](https://github.com/ryanfaerman/netctl/blob/master/internal/services/authorization.go)

I've also made a simple package with a generic form here: [https://github.com/ryanfaerman/can](https://github.com/ryanfaerman/can)
