Documentation
¶
Overview ¶
Purpose: This file implements Cross-Site Request Forgery (CSRF) protection middleware for GoStack.
Philosophy: Stateful, cookie-session authenticated applications are vulnerable to CSRF attacks where malicious third-party pages trigger unwanted mutations. Our CSRF middleware defends against this by generating a unique, cryptographically secure token stored in the session, and checking all unsafe state-changing methods (POST, PUT, DELETE, PATCH) for a matching token in request headers or POST form bodies.
Architecture: Part of the auth package. Employs the standard http.Middleware functional onion hook. Uses crypto/rand to generate 32-byte secure hexadecimal string tokens.
Choice: We chose to synchronize the session token with an un-encrypted client cookie (XSRF-TOKEN) and check both the "X-CSRF-Token" and "X-XSRF-TOKEN" headers plus the "_token" POST parameter to support both standard HTML forms and Javascript-based API clients (Axios, Fetch).
Implementation: - CSRF: middleware generator verifying CSRF tokens for mutating requests. - generateCSRFToken: private cryptographic randomness helper.
Purpose: This file defines standard, reusable sentinel error types for GoStack authentication.
Philosophy: Authentication flows should return clear, typed, and predictable error conditions. By utilizing typed sentinels, caller code (such as HTTP controllers or CLI commands) can inspect failure causes precisely (e.g. invalid password vs token expiration) and respond with appropriate HTTP status codes or message outputs.
Architecture: Part of the auth package. These errors are returned by Hasher, Guards, and UserProvider implementations.
Purpose: This file implements standard, secure password hashing for the GoStack framework using Bcrypt.
Philosophy: Password security is non-negotiable. We favor the standard, battle-tested bcrypt algorithm with configurable hashing cost (work factor). We abstract this behind the contract.Hasher interface, permitting mock hashing under tests and supporting future algorithm upgrades without modifying controller credentials logic.
Architecture: Part of the auth package. Implements contract.Hasher.
Choice: We chose bcrypt for password hashing because of its built-in resistance to brute-force hardware attacks via adaptive work factor scaling.
Purpose: This file implements the central AuthManager (Guard) coordinating multiple authentication guards.
Philosophy: A single application often requires multiple auth strategies (e.g. cookie sessions for web views, bearer tokens for mobile/API clients). Our AuthManager serves as a thread-safe registry mapping named strategies (Guards) and falling back to a configured default strategy. This provides a unified entry point similar to Laravel's Auth facade.
Architecture: Part of the auth package. Coordinates implementations of contract.Guard.
Choice: We chose to implement delegation helpers (Check, User, Login, Logout) directly on the AuthManager delegating to the default guard, keeping simple configurations extremely clean.
Implementation: - AuthManager: holds mutex-locked map of Guards with Register, Guard, and delegation helpers.
Purpose: This file implements standard routing middleware filters for GoStack authentication. It provides filters to protect routes (RequireAuth) and restrict authenticated access (Guest).
Philosophy: Access control should be transparent, declarative, and format-aware. Middleware must seamlessly handle both web requests (with redirects) and API requests (with JSON payloads) without polluting the controller logic. Caching user retrieval in the request context prevents multiple database queries on complex pipelines.
Architecture: Part of the auth package. The middleware wraps the standard GoStack http.Middleware contract. It uses standard request context propagation to pass user caches down the handler pipeline.
Choice: We chose to inspect request headers (Accept / Content-Type) and guard names to auto-detect API vs Web contexts, rather than forcing the developer to register different middleware classes.
Implementation: - RequireAuth: checks authentication, redirecting to /login or returning 401 JSON. - Guest: prevents authenticated access to auth routes, redirecting to /home.
Purpose: This file implements Session-based authentication (SessionGuard) for the GoStack framework.
Philosophy: Stateful web applications rely on cookie-based session identifiers to map requests to users. Our SessionGuard provides a secure wrapper that handles setting keys in the session, pulling user IDs out of the session, and calling the registered UserProvider. To prevent repeated database hits during a single request, the guard utilizes an in-context cache container.
Architecture: Part of the auth package. Implements contract.Guard. Interacts with contract.Session and contract.UserProvider to load and persist authentication status.
Choice: We chose request context caching using a pointer-based mutable AuthCache struct to prevent N+1 DB lookup scenarios in middlewares/controllers without mutating request contexts repeatedly.
Implementation: - SessionGuard: stores credentials checks, caching, manual Login, Logout, and Attempt actions.
Purpose: This file implements stateless API Token-based authentication (TokenGuard) for GoStack.
Philosophy: REST APIs and headless microservices should remain stateless. Our TokenGuard inspects each incoming request's headers and query parameters for active bearer tokens. Like the SessionGuard, it leverages request-scoped caching to optimize DB access during a single request lifecycle.
Architecture: Part of the auth package. Implements contract.Guard. Interacts with contract.UserProvider's RetrieveByCredentials mapping token credentials directly.
Choice: We chose to look for tokens in both the "Authorization: Bearer <token>" header and the "api_token" URL query parameter to maximize client request flexibility.
Implementation: - TokenGuard: stateless check, User retrieval, getToken parser, and no-op Login/Logout hooks.
Index ¶
- Variables
- func CSRF(cookieName string) http.Middleware
- func Guest(manager *AuthManager, guardName string) http.Middleware
- func RequireAuth(manager *AuthManager, guardName string) http.Middleware
- type AuthManager
- func (m *AuthManager) Check(r *http.Request) bool
- func (m *AuthManager) Guard(name string) contract.Guard
- func (m *AuthManager) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
- func (m *AuthManager) Logout(w http.ResponseWriter, r *http.Request) error
- func (m *AuthManager) Register(name string, guard contract.Guard)
- func (m *AuthManager) User(r *http.Request) (contract.Authenticatable, bool)
- type BcryptHasher
- type Gate
- func (g *Gate) Allows(user contract.Authenticatable, ability string, args ...any) bool
- func (g *Gate) Define(ability string, fn func(user contract.Authenticatable, args ...any) bool)
- func (g *Gate) Denies(user contract.Authenticatable, ability string, args ...any) bool
- func (g *Gate) RegisterPolicy(resourceName string, policy Policy)
- type Policy
- type SessionGuard
- func (g *SessionGuard) Attempt(w http.ResponseWriter, r *http.Request, credentials map[string]any) error
- func (g *SessionGuard) Check(r *http.Request) bool
- func (g *SessionGuard) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
- func (g *SessionGuard) Logout(w http.ResponseWriter, r *http.Request) error
- func (g *SessionGuard) User(r *http.Request) (contract.Authenticatable, bool)
- type TokenGuard
- func (g *TokenGuard) Check(r *http.Request) bool
- func (g *TokenGuard) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
- func (g *TokenGuard) Logout(w http.ResponseWriter, r *http.Request) error
- func (g *TokenGuard) User(r *http.Request) (contract.Authenticatable, bool)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidCredentials is returned when a user provides an incorrect password. ErrInvalidCredentials = errors.New("authentication failed: invalid credentials") // ErrUserNotFound is returned when no user corresponds to the provided credentials. ErrUserNotFound = errors.New("authentication failed: user not found") // ErrSessionUninitialized is returned when the session store middleware was not run before an auth guard. ErrSessionUninitialized = errors.New("authentication failed: session not initialized") // ErrInvalidToken is returned when an API token is invalid or cannot be decoded. ErrInvalidToken = errors.New("authentication failed: invalid bearer token") // ErrTokenExpired is returned when a valid API token has exceeded its expiration date. ErrTokenExpired = errors.New("authentication failed: token expired") )
Functions ¶
func CSRF ¶
func CSRF(cookieName string) http.Middleware
CSRF builds middleware that enforces Cross-Site Request Forgery protection. It matches tokens from the session against header/POST form parameters.
func Guest ¶
func Guest(manager *AuthManager, guardName string) http.Middleware
Guest redirects authenticated users away from public auth pages (e.g. login/register).
func RequireAuth ¶
func RequireAuth(manager *AuthManager, guardName string) http.Middleware
RequireAuth restricts route access to authenticated users. Unauthenticated requests receive a 401 JSON response or redirect to /login.
Types ¶
type AuthManager ¶
type AuthManager struct {
// contains filtered or unexported fields
}
AuthManager coordinates authentication across multiple named guards.
func NewAuthManager ¶
func NewAuthManager(defaultGuard string) *AuthManager
NewAuthManager initializes a fresh authentication manager coordinator.
func (*AuthManager) Check ¶
func (m *AuthManager) Check(r *http.Request) bool
Check delegates to the default guard.
func (*AuthManager) Guard ¶
func (m *AuthManager) Guard(name string) contract.Guard
Guard resolves a registered guard by name, falling back to the configured default guard.
func (*AuthManager) Login ¶
func (m *AuthManager) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
Login delegates to the default guard.
func (*AuthManager) Logout ¶
func (m *AuthManager) Logout(w http.ResponseWriter, r *http.Request) error
Logout delegates to the default guard.
func (*AuthManager) Register ¶
func (m *AuthManager) Register(name string, guard contract.Guard)
Register maps a named guard to a specific authentication strategy.
func (*AuthManager) User ¶
func (m *AuthManager) User(r *http.Request) (contract.Authenticatable, bool)
User delegates to the default guard.
type BcryptHasher ¶
type BcryptHasher struct {
// contains filtered or unexported fields
}
BcryptHasher implements contract.Hasher using the standard bcrypt package.
func NewBcryptHasher ¶
func NewBcryptHasher(cost int) *BcryptHasher
NewBcryptHasher constructs a new BcryptHasher with a specified cost factor. If cost <= 0, it defaults to bcrypt.DefaultCost.
func (*BcryptHasher) Hash ¶
func (h *BcryptHasher) Hash(plain string) (string, error)
Hash generates a secure bcrypt hash of a plain text string.
func (*BcryptHasher) Verify ¶
func (h *BcryptHasher) Verify(plain, hashed string) bool
Verify compares a plain text password against a hash in constant time.
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
Gate manages permissions and policies.
func (*Gate) RegisterPolicy ¶
RegisterPolicy registers a policy for a specific resource type name (e.g. "post").
type Policy ¶
type Policy func(user contract.Authenticatable, model any) bool
Policy defines a callback function to determine if a user has access to a specific resource.
type SessionGuard ¶
type SessionGuard struct {
// contains filtered or unexported fields
}
SessionGuard handles authentication using cookie-based session state.
func NewSessionGuard ¶
func NewSessionGuard(name string, provider contract.UserProvider) *SessionGuard
NewSessionGuard builds a new SessionGuard targeting a named guard context.
func (*SessionGuard) Attempt ¶
func (g *SessionGuard) Attempt(w http.ResponseWriter, r *http.Request, credentials map[string]any) error
Attempt validates credentials against the provider and logs the user in if correct.
func (*SessionGuard) Check ¶
func (g *SessionGuard) Check(r *http.Request) bool
Check verifies if the incoming request contains an authenticated session user.
func (*SessionGuard) Login ¶
func (g *SessionGuard) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
Login commits user details to session, signing them in.
func (*SessionGuard) Logout ¶
func (g *SessionGuard) Logout(w http.ResponseWriter, r *http.Request) error
Logout deletes user ID from session.
func (*SessionGuard) User ¶
func (g *SessionGuard) User(r *http.Request) (contract.Authenticatable, bool)
User returns the authenticated user context, retrieving from session or per-request cache.
type TokenGuard ¶
type TokenGuard struct {
// contains filtered or unexported fields
}
TokenGuard handles stateless authentication using API bearer tokens.
func NewTokenGuard ¶
func NewTokenGuard(provider contract.UserProvider) *TokenGuard
NewTokenGuard constructs a new TokenGuard with a user retrieval provider.
func (*TokenGuard) Check ¶
func (g *TokenGuard) Check(r *http.Request) bool
Check validates if the request contains a valid API token.
func (*TokenGuard) Login ¶
func (g *TokenGuard) Login(w http.ResponseWriter, r *http.Request, user contract.Authenticatable) error
Login is a stateless no-op for TokenGuard.
func (*TokenGuard) Logout ¶
func (g *TokenGuard) Logout(w http.ResponseWriter, r *http.Request) error
Logout is a stateless no-op for TokenGuard.
func (*TokenGuard) User ¶
func (g *TokenGuard) User(r *http.Request) (contract.Authenticatable, bool)
User extracts the bearer token, retrieves the matching user, and caches them in request context.