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

authorization

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package authorization decides whether the identity in a request context may proceed. A Check is a function of the context, so the same check guards HTTP routes, WebSocket messages, jobs and tests. Checks compose with All, Any, Not and Real; the primitives read the auth.Identity a provider put into the context.

Refusals are *auth.Error: ErrUnauthenticated when there is no identity, ErrForbidden otherwise, with a Reason for the wide event that never reaches the client. Not and every primitive except IsAuthenticated require an active identity, so a deactivated admin is not an admin. A wiring mistake (a nil Check, All or Any without checks, HasPermission with an invalid permission) fails with a plain error, answered 500, so it fails closed and Not cannot invert it into a pass.

Entity checks (may this identity see this object) stay in the applications. Checks are pure and safe for concurrent use.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Check

type Check func(ctx context.Context) error

Check decides whether the identity in ctx may proceed: nil allows, an error refuses. Refusals are *auth.Error with Kind ErrUnauthenticated (no identity) or ErrForbidden (Reason says why).

func All

func All(checks ...Check) Check

All passes when every check passes and returns the first refusal or failure otherwise. Without checks it fails (a wiring mistake).

Example
package main

import (
	"context"
	"fmt"

	"github.com/govengers/auth"
	"github.com/govengers/auth/authorization"
)

func main() {
	editor := authorization.All(authorization.HasOIDCGroup("/engineering"), authorization.Not(authorization.HasOIDCRole("read-only")))

	engineer := auth.WithIdentity(context.Background(), &auth.Identity{Provider: "keycloak", Subject: "1", Active: true, Groups: []string{"/engineering"}})
	reader := auth.WithIdentity(context.Background(), &auth.Identity{Provider: "keycloak", Subject: "2", Active: true, Groups: []string{"/engineering"}, OIDCRoles: []string{"read-only"}})

	fmt.Println(editor(engineer))
	status, response := auth.ResponseFor(editor(reader))
	fmt.Println(status, response.Code)
}
Output:
<nil>
403 forbidden

func Any

func Any(checks ...Check) Check

Any passes when one check passes. When none does it returns the first failure (an error answered 500: that check decided nothing, so Not must not invert the result), else the first refusal. Without checks it fails (a wiring mistake).

Example
package main

import (
	"context"
	"fmt"

	"github.com/google/uuid"

	"github.com/govengers/auth"
	"github.com/govengers/auth/authorization"
)

func main() {
	ownerID := uuid.MustParse("0b6f2c1e-7a3d-4c55-9f0e-2d8b1a6c4e71")
	ownerOrAdmin := authorization.Any(authorization.IsAdmin(), authorization.HasUserID(ownerID))

	owner := auth.WithIdentity(context.Background(), &auth.Identity{Provider: "password", Subject: "ada", UserID: ownerID, Active: true})
	stranger := auth.WithIdentity(context.Background(), &auth.Identity{Provider: "password", Subject: "eve", UserID: uuid.New(), Active: true})

	fmt.Println(ownerOrAdmin(owner))
	fmt.Println(ownerOrAdmin(stranger))
	fmt.Println(ownerOrAdmin(context.Background()))
}
Output:
<nil>
forbidden: missing role admin
unauthenticated: no identity

func HasGitHubTeam

func HasGitHubTeam(team string) Check

HasGitHubTeam passes an active identity that is a member of team ("org/team-slug", matched case-insensitively; the GitHub provider stores Teams in lower case).

func HasOIDCGroup

func HasOIDCGroup(group string) Check

HasOIDCGroup passes an active identity with group in Groups.

func HasOIDCRole

func HasOIDCRole(role string) Check

HasOIDCRole passes an active identity with role in OIDCRoles (Keycloak realm roles).

func HasPermission

func HasPermission(resource string, access auth.Access) Check

HasPermission passes an active identity that Permits access on resource (auth.Permission.Grants: "*" covers every resource, write includes read). An empty or invalid resource, or an access other than read and write, is a wiring mistake: every request fails. The effective identity counts; wrap the check in Real to check the impersonator. Interactive users have no permissions unless an OnLogin hook grants them: compose Any(HasRole(role), HasPermission(resource, access)) or grant them at login.

Example
package main

import (
	"context"
	"fmt"

	"github.com/govengers/auth"
	"github.com/govengers/auth/authorization"
)

func main() {
	continuousIntegration := auth.WithIdentity(context.Background(), &auth.Identity{
		Provider:    "apikey",
		Subject:     "ci",
		Active:      true,
		Permissions: []auth.Permission{{Resource: "builds", Access: auth.AccessWrite}, {Resource: "*", Access: auth.AccessRead}},
	})

	fmt.Println(authorization.HasPermission("builds", auth.AccessWrite)(continuousIntegration))
	fmt.Println(authorization.HasPermission("deployments", auth.AccessRead)(continuousIntegration))
	fmt.Println(authorization.HasPermission("deployments", auth.AccessWrite)(continuousIntegration))
}
Output:
<nil>
<nil>
forbidden: missing permission deployments:write

func HasRole

func HasRole(role string) Check

HasRole passes an active identity with role in Roles.

func HasUserID

func HasUserID(id uuid.UUID) Check

HasUserID passes an active identity whose UserID is id. uuid.Nil never matches, so an identity without an application user ID never owns anything.

func IsActive

func IsActive() Check

IsActive passes an active identity.

func IsAdmin

func IsAdmin() Check

IsAdmin passes an active identity with the role auth.RoleAdmin.

func IsAuthenticated

func IsAuthenticated() Check

IsAuthenticated passes any identity, active or not.

func IsUser

func IsUser() Check

IsUser passes an active identity; it is IsActive under the name application code uses for "any user".

func Not

func Not(check Check) Check

Not inverts check for an active identity: it passes when check refuses with ErrForbidden and refuses with ErrForbidden when check passes; other errors pass through. The refusal is classified like auth.ResponseFor does, by the Kind of the outermost *auth.Error, so an unauthenticated refusal with a forbidden cause is no forbidden refusal. Like the primitives it refuses a missing identity with ErrUnauthenticated and an inactive one with ErrForbidden before it evaluates check, so Not(HasRole(role)) never admits an anonymous or deactivated identity.

func Real

func Real(check Check) Check

Real evaluates check against the identity that authenticated: the impersonator while impersonating, the identity itself otherwise. Real(IsAdmin()) keeps an impersonating admin an admin.

Jump to

Keyboard shortcuts

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