Documentation
¶
Overview ¶
Package guard wires identity, sessions, RBAC/ABAC and audit into one entry point.
g, _ := guard.New(guard.Config{DB: pool, Redis: rdb, UserTable: "users", UserIDColumn: "id"})
_, _ = g.WriteMigrations(ctx, "./migrations/guard") // detects users.id type, renders SQL
_ = g.Migrate(ctx, "./migrations/guard")
ginguard.Mount(router.Group("/api"), g, ginguard.Options{})
Index ¶
- Constants
- Variables
- type APIKey
- type APIKeyToken
- type AccessCacheOptions
- type AccessCacheStats
- type AuditBuffer
- type AuditEvent
- type Config
- type Decision
- type Guard
- func (g *Guard) AccessStats() (stats accessinfra.CacheStats, ok bool)
- func (g *Guard) AssignRole(ctx context.Context, actorID, userID, role string, expiresAt *time.Time) error
- func (g *Guard) Authenticate(ctx context.Context, credential string) (*Principal, error)
- func (g *Guard) Authorize(ctx context.Context, p *Principal, action string, res Resource, ...) (Decision, error)
- func (g *Guard) Close(ctx context.Context) error
- func (g *Guard) CreateAccount(ctx context.Context, userID, email, password string, attrs map[string]any, ...) (*User, error)
- func (g *Guard) EnsureAdmin(ctx context.Context, userID, email, password string) (*User, error)
- func (g *Guard) EnsureSuperAdmin(ctx context.Context, userID, email, password string) (*User, error)
- func (g *Guard) Health(ctx context.Context) error
- func (g *Guard) InvalidateAccess(ctx context.Context) error
- func (g *Guard) IsSuperAdmin(ctx context.Context, userID string) (bool, error)
- func (g *Guard) IssueAPIKey(ctx context.Context, p *Principal, name string, scopes []string, ...) (*APIKey, APIKeyToken, error)
- func (g *Guard) ListRoutes(ctx context.Context) ([]RouteRecord, error)
- func (g *Guard) Login(ctx context.Context, email, password string, meta RequestMeta) (*LoginResult, error)
- func (g *Guard) Logout(ctx context.Context, p *Principal, meta RequestMeta) error
- func (g *Guard) Migrate(ctx context.Context, dir string) error
- func (g *Guard) ResetPassword(ctx context.Context, actorID, userID, password string) error
- func (g *Guard) RotateSession(ctx context.Context, token SessionToken) (*Session, SessionToken, error)
- func (g *Guard) SetAttributes(ctx context.Context, actorID, userID string, attrs map[string]any) error
- func (g *Guard) SetUserStatus(ctx context.Context, actorID, userID string, status Status) error
- func (g *Guard) SuperAdmins(ctx context.Context) ([]string, error)
- func (g *Guard) SyncRoutes(ctx context.Context, routes []Route, o RouteSyncOptions) (RouteSyncResult, error)
- func (g *Guard) UnassignRole(ctx context.Context, actorID, userID, role string) error
- func (g *Guard) UserRef(ctx context.Context) (migrations.UserRef, error)
- func (g *Guard) WriteMigrations(ctx context.Context, dir string) ([]string, error)
- type Lockout
- type LoginResult
- type PasswordHashParams
- type Permission
- type Policy
- type Principal
- type Repositories
- type RequestMeta
- type Resource
- type Role
- type RoleGrant
- type Route
- type RouteRecord
- type RouteSyncOptions
- type RouteSyncResult
- type Session
- type SessionPolicy
- type SessionToken
- type Status
- type User
Constants ¶
const RoleSuperAdmin = accessdomain.RoleSuperAdmin
RoleSuperAdmin is the system role that alone manages admin and super_admin grants.
Variables ¶
var ( ErrForbidden = accessdomain.ErrForbidden ErrLastSuperAdmin = accessdomain.ErrLastSuperAdmin ErrSuperAdminExpiry = accessdomain.ErrSuperAdminExpiry )
Super admin errors, re-exported for HTTP error mapping.
var ErrNoRouteRegistry = errors.New("guard: route registry needs a PostgreSQL-backed Guard")
ErrNoRouteRegistry is returned by ListRoutes on a Guard without PostgreSQL.
var ErrSessionRequired = errors.New("guard: this operation requires a session, not an API key")
Functions ¶
This section is empty.
Types ¶
type APIKey ¶
type APIKey = apikeydomain.Key
Re-exported domain types so host apps need a single import.
type APIKeyToken ¶
type APIKeyToken = apikeydomain.Token
Re-exported domain types so host apps need a single import.
type AccessCacheOptions ¶
type AccessCacheOptions = accessinfra.CacheOptions
AccessCacheOptions configures Config.AccessCache.
type AccessCacheStats ¶
type AccessCacheStats = accessinfra.CacheStats
Re-exported domain types so host apps need a single import.
type AuditBuffer ¶
AuditBuffer configures the Redis-backed audit queue. Events are pushed to the Redis list <RedisPrefix>audit:queue and flushed every Interval (default 1s) in batches of BatchSize (default 500). The queue survives process restarts and is shared by every instance. When Redis is unavailable events fall back to direct PostgreSQL writes. Call Guard.Close on shutdown to drain it.
type AuditEvent ¶
Re-exported domain types so host apps need a single import.
type Config ¶
type Config struct {
DB *pgxpool.Pool
Redis redis.UniversalClient
// RedisPrefix namespaces session keys. Default "guard:".
RedisPrefix string
// Session lifetime. Each zero field uses its default (30m idle / 7d absolute).
Session SessionPolicy
// Lockout for password guessing. Each zero field uses its default (5 attempts / 15m).
Lockout Lockout
// DefaultRole is assigned on CreateAccount. Default "user"; "-" disables.
DefaultRole string
// UserTable is the host application's existing user table ("users" or
// "schema.users"). Guard never creates it; its tables reference it. Default "users".
UserTable string
// UserIDColumn is the primary key (or unique) column of UserTable. Default "id".
UserIDColumn string
// Logger receives operational events (audit write failures at Warn, failed
// logins at Info). Raw emails, passwords and tokens are never logged.
// Default slog.Default().
Logger *slog.Logger
// AsyncAudit > 0 writes audit events through a non-blocking buffer of this
// size; overflow is dropped and counted. 0 (default) writes synchronously.
// Call Guard.Close on shutdown to flush.
AsyncAudit int
// AuditBuffer queues audit events in Redis and batch-writes them to
// PostgreSQL. When Enabled, AsyncAudit is ignored.
AuditBuffer AuditBuffer
// AccessCache enables the in-process role/policy cache for authorization
// (invalidated cluster-wide through Redis). nil (default) disables it.
// Empty Prefix uses RedisPrefix; nil OnError logs at Warn.
AccessCache *accessinfra.CacheOptions
// PasswordHashParams overrides argon2id parameters; values below the OWASP
// floor make New fail. nil uses secure defaults. Legacy bcrypt hashes are
// always verified and upgraded on login.
PasswordHashParams *PasswordHashParams
// AuditEmailKey (>= 32 random bytes, keep secret) makes login audit events
// store "email_hmac" (hex HMAC-SHA256, first 16 bytes) instead of the
// unkeyed "email_sha256" fingerprint, which is brute-forceable from a list
// of known addresses. Raw emails are never stored in audit metadata.
AuditEmailKey []byte
}
type Decision ¶
type Decision = accessdomain.Decision
Re-exported domain types so host apps need a single import.
type Guard ¶
type Guard struct {
Identity *identityapp.Service
Sessions *sessionapp.Service
Access *accessapp.Service
APIKeys *apikeyapp.Service
Audit audit.Log
// Limiter is nil when no Redis-backed limiter was configured.
Limiter ratelimit.Limiter
// contains filtered or unexported fields
}
func Build ¶
func Build(r Repositories, cfg Config) *Guard
func (*Guard) AccessStats ¶
func (g *Guard) AccessStats() (stats accessinfra.CacheStats, ok bool)
AccessStats returns access cache counters; ok is false when Config.AccessCache is nil.
func (*Guard) AssignRole ¶
func (g *Guard) AssignRole(ctx context.Context, actorID, userID, role string, expiresAt *time.Time) error
AssignRole grants role to userID on behalf of actorID and audits it. Granting admin or super_admin requires a super admin actor (ErrForbidden).
func (*Guard) Authenticate ¶
Authenticate resolves a session token or an API key ("gk_...") into a principal. The user row is re-read on every call so bans and role changes apply immediately.
func (*Guard) Authorize ¶
func (g *Guard) Authorize(ctx context.Context, p *Principal, action string, res Resource, env map[string]any) (Decision, error)
Authorize decides whether p may perform action on resource.
func (*Guard) Close ¶
Close flushes buffered audit events (Config.AsyncAudit, Config.AuditBuffer) until done or ctx expires. It never closes the caller's database pool or Redis client.
func (*Guard) CreateAccount ¶
func (g *Guard) CreateAccount(ctx context.Context, userID, email, password string, attrs map[string]any, meta RequestMeta) (*User, error)
CreateAccount gives an existing host user (userID from UserTable) login credentials, assigns DefaultRole and records an audit event.
func (*Guard) EnsureAdmin ¶
EnsureAdmin gives the existing host user userID an account (if missing) and the admin role. Intended for bootstrap at startup.
func (*Guard) EnsureSuperAdmin ¶
func (g *Guard) EnsureSuperAdmin(ctx context.Context, userID, email, password string) (*User, error)
EnsureSuperAdmin gives the existing host user userID an account (if missing) and the super_admin role. Idempotent; intended for bootstrap (e.g. GUARD_SUPERADMIN_EMAIL / GUARD_SUPERADMIN_PASSWORD at startup). An existing account keeps its password.
func (*Guard) Health ¶
Health pings PostgreSQL and Redis, each with a 2s timeout. It returns an error naming every unhealthy backend, or when none is configured.
func (*Guard) InvalidateAccess ¶
InvalidateAccess drops cached role grants and policies on every instance. Call it after changes that bypass Guard, e.g. deleting a host user (ON DELETE CASCADE). No-op without Config.AccessCache.
func (*Guard) IsSuperAdmin ¶
IsSuperAdmin reports whether userID actively holds super_admin.
func (*Guard) IssueAPIKey ¶
func (g *Guard) IssueAPIKey(ctx context.Context, p *Principal, name string, scopes []string, expiresAt *time.Time, meta RequestMeta) (*APIKey, APIKeyToken, error)
IssueAPIKey creates a key for p's user. Only session principals may issue keys, so a leaked key cannot mint more keys.
func (*Guard) ListRoutes ¶
func (g *Guard) ListRoutes(ctx context.Context) ([]RouteRecord, error)
ListRoutes returns the route registry, stale routes included.
func (*Guard) Login ¶
func (g *Guard) Login(ctx context.Context, email, password string, meta RequestMeta) (*LoginResult, error)
func (*Guard) Migrate ¶
Migrate applies migrations from dir. dir == "" renders the embedded templates against the detected user table instead.
func (*Guard) ResetPassword ¶
ResetPassword sets a new password (admin action), signs the user out everywhere and revokes every API key of the user. Resetting an admin or super admin needs a super admin actor (ErrForbidden).
func (*Guard) RotateSession ¶
func (g *Guard) RotateSession(ctx context.Context, token SessionToken) (*Session, SessionToken, error)
RotateSession replaces a session token (call after login or privilege change) and records session.rotate. The old token stops working.
func (*Guard) SetAttributes ¶
func (g *Guard) SetAttributes(ctx context.Context, actorID, userID string, attrs map[string]any) error
SetAttributes replaces userID's ABAC attributes on behalf of actorID. Attributes feed ABAC decisions, so users may not change their own unless they are a super admin (ErrForbidden).
func (*Guard) SetUserStatus ¶
SetUserStatus changes account status; blocking also revokes every session. Changing an admin or super admin needs a super admin actor (ErrForbidden).
func (*Guard) SuperAdmins ¶
SuperAdmins returns the user ids holding super_admin.
func (*Guard) SyncRoutes ¶
func (g *Guard) SyncRoutes(ctx context.Context, routes []Route, o RouteSyncOptions) (RouteSyncResult, error)
SyncRoutes discovers route permissions (see accessapp.Service.SyncRoutes): admin and super_admin get every route permission, the user role gets UserActions (default read) for new routes, and removed routes are marked stale. Idempotent; safe to call at every startup. Records a routes.sync audit event.
func (*Guard) UnassignRole ¶
UnassignRole revokes role from userID on behalf of actorID and audits it. Revoking admin or super_admin requires a super admin actor (ErrForbidden); the last super admin keeps the role (ErrLastSuperAdmin).
type Lockout ¶
type Lockout = identitydomain.Lockout
Re-exported domain types so host apps need a single import.
type LoginResult ¶
type LoginResult struct {
User *User
Session *Session
Token SessionToken
}
type PasswordHashParams ¶
PasswordHashParams are argon2id parameters (Memory in KiB).
type Permission ¶
type Permission = accessdomain.Permission
Re-exported domain types so host apps need a single import.
type Policy ¶
type Policy = accessdomain.Policy
Re-exported domain types so host apps need a single import.
type Principal ¶
Principal is the authenticated caller of a request. Exactly one of Session and APIKey is set.
type Repositories ¶
type Repositories struct {
Users identitydomain.UserRepository
Hasher identitydomain.PasswordHasher
Sessions sessiondomain.Repository
Roles accessdomain.RoleRepository
Policies accessdomain.PolicyRepository
Audit audit.Log
APIKeys apikeydomain.Repository
Limiter ratelimit.Limiter
}
Repositories lets callers swap storage (tests, other databases).
type RequestMeta ¶
RequestMeta describes the HTTP caller for sessions and audit.
type Resource ¶
type Resource = accessdomain.Resource
Re-exported domain types so host apps need a single import.
type Role ¶
type Role = accessdomain.Role
Re-exported domain types so host apps need a single import.
type RoleGrant ¶
type RoleGrant = accessdomain.RoleGrant
Re-exported domain types so host apps need a single import.
type RouteRecord ¶
type RouteRecord = accessdomain.RouteRecord
type RouteSyncOptions ¶
type RouteSyncOptions = accessapp.RouteSyncOptions
type RouteSyncResult ¶
type RouteSyncResult = accessapp.RouteSyncResult
type Session ¶
type Session = sessiondomain.Session
Re-exported domain types so host apps need a single import.
type SessionPolicy ¶
type SessionPolicy = sessiondomain.Policy
Re-exported domain types so host apps need a single import.
type SessionToken ¶
type SessionToken = sessiondomain.Token
Re-exported domain types so host apps need a single import.
type Status ¶
type Status = identitydomain.Status
Re-exported domain types so host apps need a single import.
type User ¶
type User = identitydomain.User
Re-exported domain types so host apps need a single import.
Directories
¶
| Path | Synopsis |
|---|---|
|
access
|
|
|
application
Package application contains authorization use cases.
|
Package application contains authorization use cases. |
|
domain
Package domain holds authorization rules: RBAC roles/permissions and ABAC policies.
|
Package domain holds authorization rules: RBAC roles/permissions and ABAC policies. |
|
infrastructure
Package infrastructure stores roles, permissions and policies in PostgreSQL.
|
Package infrastructure stores roles, permissions and policies in PostgreSQL. |
|
adapters
|
|
|
beego
module
|
|
|
echo
module
|
|
|
fiber
module
|
|
|
hertz
module
|
|
|
iris
module
|
|
|
Package adminui is a server-rendered (html/template) admin panel for Guard: users, RBAC, ABAC policies, sessions, API keys and audit.
|
Package adminui is a server-rendered (html/template) admin panel for Guard: users, RBAC, ABAC policies, sessions, API keys and audit. |
|
apikey
|
|
|
application
Package application contains API key use cases.
|
Package application contains API key use cases. |
|
domain
Package domain holds API key rules: issuance, scopes, expiry, revocation.
|
Package domain holds API key rules: issuance, scopes, expiry, revocation. |
|
infrastructure
Package infrastructure stores API keys in PostgreSQL (or memory for tests).
|
Package infrastructure stores API keys in PostgreSQL (or memory for tests). |
|
Package audit records security events (logins, role changes, policy edits).
|
Package audit records security events (logins, role changes, policy edits). |
|
Package config loads a guard.yaml file and wires Guard from it.
|
Package config loads a guard.yaml file and wires Guard from it. |
|
examples
|
|
|
gin
command
Command gin runs Guard's HTTP API on Gin, configured from a YAML file.
|
Command gin runs Guard's HTTP API on Gin, configured from a YAML file. |
|
Package ginguard exposes Guard over Gin: ready-made auth/admin routes and middleware.
|
Package ginguard exposes Guard over Gin: ready-made auth/admin routes and middleware. |
|
Package guardtest builds a Guard on in-memory storage (plus a Redis client for sessions) seeded like the SQL migrations.
|
Package guardtest builds a Guard on in-memory storage (plus a Redis client for sessions) seeded like the SQL migrations. |
|
Package httpguard exposes Guard over net/http: ready-made auth/admin routes and middleware built on http.Handler, with no web framework dependency.
|
Package httpguard exposes Guard over net/http: ready-made auth/admin routes and middleware built on http.Handler, with no web framework dependency. |
|
identity
|
|
|
application
Package application contains identity use cases.
|
Package application contains identity use cases. |
|
domain
Package domain holds identity business rules: users, credentials, lockout.
|
Package domain holds identity business rules: users, credentials, lockout. |
|
infrastructure
Package infrastructure provides identity adapters: argon2id hashing and PostgreSQL storage.
|
Package infrastructure provides identity adapters: argon2id hashing and PostgreSQL storage. |
|
kernel
|
|
|
migrations
Package migrations ships Guard's PostgreSQL schema as goose migrations.
|
Package migrations ships Guard's PostgreSQL schema as goose migrations. |
|
pgerr
Package pgerr classifies PostgreSQL errors returned through pgx.
|
Package pgerr classifies PostgreSQL errors returned through pgx. |
|
Package ratelimit throttles requests with a Redis sliding-window log.
|
Package ratelimit throttles requests with a Redis sliding-window log. |
|
session
|
|
|
application
Package application contains session use cases.
|
Package application contains session use cases. |
|
domain
Package domain holds session business rules: lifetime, idle timeout, revocation.
|
Package domain holds session business rules: lifetime, idle timeout, revocation. |
|
infrastructure
Package infrastructure stores sessions in Redis.
|
Package infrastructure stores sessions in Redis. |