security

package
v1.0.52 Latest Latest
Warning

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

Go to latest
Published: Feb 10, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

README

ResolveSpec Security Provider

Type-safe, composable security system for ResolveSpec with support for authentication, column-level security (masking), and row-level security (filtering).

Features

  • Interface-Based - Type-safe providers instead of callbacks
  • Login/Logout Support - Built-in authentication lifecycle
  • Two-Factor Authentication (2FA) - Optional TOTP support for enhanced security
  • Composable - Mix and match different providers
  • No Global State - Each handler has its own security configuration
  • Testable - Easy to mock and test
  • Extensible - Implement custom providers for your needs
  • Stored Procedures - All database operations use PostgreSQL stored procedures for security and maintainability

Stored Procedure Architecture

All database-backed security providers use PostgreSQL stored procedures exclusively. No raw SQL queries are executed from Go code.

Benefits
  • Security: Database logic is centralized and protected
  • Maintainability: Update database logic without recompiling Go code
  • Performance: Stored procedures are pre-compiled and optimized
  • Testability: Test database logic independently
  • Consistency: Standardized resolvespec_* naming convention
Available Stored Procedures
Procedure Purpose Used By
resolvespec_login Session-based login DatabaseAuthenticator
resolvespec_logout Session invalidation DatabaseAuthenticator
resolvespec_session Session validation DatabaseAuthenticator
resolvespec_session_update Update session activity DatabaseAuthenticator
resolvespec_refresh_token Token refresh DatabaseAuthenticator
resolvespec_jwt_login JWT user validation JWTAuthenticator
resolvespec_jwt_logout JWT token blacklist JWTAuthenticator
resolvespec_column_security Load column rules DatabaseColumnSecurityProvider
resolvespec_row_security Load row templates DatabaseRowSecurityProvider

See database_schema.sql for complete stored procedure definitions and examples.

Quick Start

import (
    "github.com/bitechdev/ResolveSpec/pkg/security"
    "github.com/bitechdev/ResolveSpec/pkg/restheadspec"
)

// 1. Create security providers
auth := security.NewJWTAuthenticator("your-secret-key", db)
colSec := security.NewDatabaseColumnSecurityProvider(db)
rowSec := security.NewDatabaseRowSecurityProvider(db)

// 2. Combine providers
provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)

// 3. Create handler and register security hooks
handler := restheadspec.NewHandlerWithGORM(db)
securityList := security.NewSecurityList(provider)
restheadspec.RegisterSecurityHooks(handler, securityList)

// 4. Apply middleware
router := mux.NewRouter()
restheadspec.SetupMuxRoutes(router, handler)
router.Use(security.NewAuthMiddleware(securityList))
router.Use(security.SetSecurityMiddleware(securityList))

Architecture

Spec-Agnostic Design

The security system is completely spec-agnostic - it doesn't depend on any specific spec implementation. Instead, each spec (restheadspec, funcspec, resolvespec) implements its own security integration by adapting to the SecurityContext interface.

┌─────────────────────────────────────┐
│     Security Package (Generic)      │
│  - SecurityContext interface        │
│  - Security providers                │
│  - Core security logic               │
└─────────────────────────────────────┘
           ▲          ▲          ▲
           │          │          │
    ┌──────┘          │          └──────┐
    │                 │                 │
┌───▼────┐      ┌────▼─────┐     ┌────▼──────┐
│RestHead│      │ FuncSpec │     │ResolveSpec│
│  Spec  │      │          │     │           │
│        │      │          │     │           │
│Adapts  │      │ Adapts   │     │  Adapts   │
│to      │      │ to       │     │  to       │
│Security│      │ Security │     │  Security │
│Context │      │ Context  │     │  Context  │
└────────┘      └──────────┘     └───────────┘

Benefits:

  • ✅ No circular dependencies
  • ✅ Each spec can customize security integration
  • ✅ Easy to add new specs
  • ✅ Security logic is reusable across all specs
Core Interfaces

The security system is built on three main interfaces:

1. Authenticator

Handles user authentication lifecycle:

type Authenticator interface {
    Login(ctx context.Context, req LoginRequest) (*LoginResponse, error)
    Logout(ctx context.Context, req LogoutRequest) error
    Authenticate(r *http.Request) (*UserContext, error)
}
2. ColumnSecurityProvider

Manages column-level security (masking/hiding):

type ColumnSecurityProvider interface {
    GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)
}
3. RowSecurityProvider

Manages row-level security (WHERE clause filtering):

type RowSecurityProvider interface {
    GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)
}
SecurityProvider

The main interface that combines all three:

type SecurityProvider interface {
    Authenticator
    ColumnSecurityProvider
    RowSecurityProvider
}
4. SecurityContext (Spec Integration Interface)

Each spec implements this interface to integrate with the security system:

type SecurityContext interface {
    GetContext() context.Context
    GetUserID() (int, bool)
    GetSchema() string
    GetEntity() string
    GetModel() interface{}
    GetQuery() interface{}
    SetQuery(interface{})
    GetResult() interface{}
    SetResult(interface{})
}

Implementation Examples:

  • restheadspec: Adapts restheadspec.HookContextSecurityContext
  • funcspec: Adapts funcspec.HookContextSecurityContext
  • resolvespec: Adapts resolvespec.HookContextSecurityContext
UserContext

Enhanced user context with complete user information:

type UserContext struct {
    UserID    int            // User's unique ID
    UserName  string         // Username
    UserLevel int            // User privilege level
    SessionID string         // Current session ID
    RemoteID  string         // Remote system ID
    Roles     []string       // User roles
    Email     string         // User email
    Claims    map[string]any // Additional authentication claims
    Meta      map[string]any // Additional metadata (can hold any JSON-serializable values)
}

Available Implementations

Authenticators

HeaderAuthenticator - Simple header-based authentication:

auth := security.NewHeaderAuthenticator()
// Expects: X-User-ID, X-User-Name, X-User-Level, etc.

DatabaseAuthenticator - Database session-based authentication (Recommended):

auth := security.NewDatabaseAuthenticator(db)
// Supports: Login, Logout, Session management, Token refresh
// All operations use stored procedures: resolvespec_login, resolvespec_logout,
// resolvespec_session, resolvespec_session_update, resolvespec_refresh_token
// Requires: users and user_sessions tables + stored procedures (see database_schema.sql)

JWTAuthenticator - JWT token authentication with login/logout:

auth := security.NewJWTAuthenticator("secret-key", db)
// Supports: Login, Logout, JWT token validation
// All operations use stored procedures: resolvespec_jwt_login, resolvespec_jwt_logout
// Note: Requires JWT library installation for token signing/verification

TwoFactorAuthenticator - Wraps any authenticator with TOTP 2FA:

baseAuth := security.NewDatabaseAuthenticator(db)

// Use in-memory provider (for testing)
tfaProvider := security.NewMemoryTwoFactorProvider(nil)

// Or use database provider (for production)
tfaProvider := security.NewDatabaseTwoFactorProvider(db, nil)
// Requires: users table with totp fields, user_totp_backup_codes table
// Requires: resolvespec_totp_* stored procedures (see totp_database_schema.sql)

auth := security.NewTwoFactorAuthenticator(baseAuth, tfaProvider, nil)
// Supports: TOTP codes, backup codes, QR code generation
// Compatible with Google Authenticator, Microsoft Authenticator, Authy, etc.
Column Security Providers

DatabaseColumnSecurityProvider - Loads rules from database:

colSec := security.NewDatabaseColumnSecurityProvider(db)
// Uses stored procedure: resolvespec_column_security
// Queries core.secaccess and core.hub_link tables

ConfigColumnSecurityProvider - Static configuration:

rules := map[string][]security.ColumnSecurity{
    "public.employees": {
        {Path: []string{"ssn"}, Accesstype: "mask", MaskStart: 5},
    },
}
colSec := security.NewConfigColumnSecurityProvider(rules)
Row Security Providers

DatabaseRowSecurityProvider - Loads filters from database:

rowSec := security.NewDatabaseRowSecurityProvider(db)
// Uses stored procedure: resolvespec_row_security

ConfigRowSecurityProvider - Static templates:

templates := map[string]string{
    "public.orders": "user_id = {UserID}",
}
blocked := map[string]bool{
    "public.admin_logs": true,
}
rowSec := security.NewConfigRowSecurityProvider(templates, blocked)

Usage Examples

Example 1: Complete Database-Backed Security with Sessions (restheadspec)
func main() {
    db := setupDatabase()

    // Run migrations (see database_schema.sql)
    // db.Exec("CREATE TABLE users ...")
    // db.Exec("CREATE TABLE user_sessions ...")

    // Create handler
    handler := restheadspec.NewHandlerWithGORM(db)

    // Create security providers
    auth := security.NewDatabaseAuthenticator(db) // Session-based auth
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks for this spec
    restheadspec.RegisterSecurityHooks(handler, securityList)

    // Setup routes
    router := mux.NewRouter()

    // Add auth endpoints
    router.HandleFunc("/auth/login", handleLogin(securityList)).Methods("POST")
    router.HandleFunc("/auth/logout", handleLogout(securityList)).Methods("POST")
    router.HandleFunc("/auth/refresh", handleRefresh(securityList)).Methods("POST")

    // Setup API with security
    apiRouter := router.PathPrefix("/api").Subrouter()
    restheadspec.SetupMuxRoutes(apiRouter, handler)
    apiRouter.Use(security.NewAuthMiddleware(securityList))
    apiRouter.Use(security.SetSecurityMiddleware(securityList))

    http.ListenAndServe(":8080", router)
}

func handleLogin(securityList *security.SecurityList) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req security.LoginRequest
        json.NewDecoder(r.Body).Decode(&req)

        // Add client info to claims
        req.Claims = map[string]any{
            "ip_address": r.RemoteAddr,
            "user_agent": r.UserAgent(),
        }

        resp, err := securityList.Provider().Login(r.Context(), req)
        if err != nil {
            http.Error(w, err.Error(), http.StatusUnauthorized)
            return
        }

        // Set session cookie (optional)
        http.SetCookie(w, &http.Cookie{
            Name:     "session_token",
            Value:    resp.Token,
            Expires:  time.Now().Add(24 * time.Hour),
            HttpOnly: true,
            Secure:   true, // Use in production with HTTPS
            SameSite: http.SameSiteStrictMode,
        })

        json.NewEncoder(w).Encode(resp)
    }
}

func handleRefresh(securityList *security.SecurityList) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Refresh-Token")

        if refreshable, ok := securityList.Provider().(security.Refreshable); ok {
            resp, err := refreshable.RefreshToken(r.Context(), token)
            if err != nil {
                http.Error(w, err.Error(), http.StatusUnauthorized)
                return
}

Two-Factor Authentication (2FA)

Overview
  • Optional per-user - Enable/disable 2FA individually
  • TOTP standard - Compatible with Google Authenticator, Microsoft Authenticator, Authy, 1Password, etc.
  • Configurable - SHA1/SHA256/SHA512, 6/8 digits, custom time periods
  • Backup codes - One-time recovery codes with secure hashing
  • Clock skew - Handles time differences between client/server
Setup
// 1. Wrap existing authenticator with 2FA support
baseAuth := security.NewDatabaseAuthenticator(db)
tfaProvider := security.NewMemoryTwoFactorProvider(nil) // Use custom DB implementation in production
tfaAuth := security.NewTwoFactorAuthenticator(baseAuth, tfaProvider, nil)

// 2. Use as normal authenticator
provider := security.NewCompositeSecurityProvider(tfaAuth, colSec, rowSec)
securityList := security.NewSecurityList(provider)
Enable 2FA for User
// 1. Initiate 2FA setup
secret, err := tfaAuth.Setup2FA(userID, "MyApp", "user@example.com")
// Returns: secret.Secret, secret.QRCodeURL, secret.BackupCodes

// 2. User scans QR code with authenticator app
// Display secret.QRCodeURL as QR code image

// 3. User enters verification code from app
code := "123456" // From authenticator app
err = tfaAuth.Enable2FA(userID, secret.Secret, code)
// 2FA is now enabled for this user

// 4. Store backup codes securely and show to user once
// Display: secret.BackupCodes (10 codes)
Login Flow with 2FA
// 1. User provides credentials
req := security.LoginRequest{
    Username: "user@example.com",
    Password: "password",
}

resp, err := tfaAuth.Login(ctx, req)

// 2. Check if 2FA required
if resp.Requires2FA {
    // Prompt user for 2FA code
    code := getUserInput() // From authenticator app or backup code
    
    // 3. Login again with 2FA code
    req.TwoFactorCode = code
    resp, err = tfaAuth.Login(ctx, req)
    
    // 4. Success - token is returned
    token := resp.Token
}
Manage 2FA
// Disable 2FA
err := tfaAuth.Disable2FA(userID)

// Regenerate backup codes
newCodes, err := tfaAuth.RegenerateBackupCodes(userID, 10)

// Check status
has2FA, err := tfaProvider.Get2FAStatus(userID)
Custom 2FA Storage

Option 1: Use DatabaseTwoFactorProvider (Recommended)

// Uses PostgreSQL stored procedures for all operations
db := setupDatabase()

// Run migrations from totp_database_schema.sql
// - Add totp_secret, totp_enabled, totp_enabled_at to users table
// - Create user_totp_backup_codes table
// - Create resolvespec_totp_* stored procedures

tfaProvider := security.NewDatabaseTwoFactorProvider(db, nil)
tfaAuth := security.NewTwoFactorAuthenticator(baseAuth, tfaProvider, nil)

Option 2: Implement Custom Provider

Implement TwoFactorAuthProvider for custom storage:

type DBTwoFactorProvider struct {
    db *gorm.DB
}

func (p *DBTwoFactorProvider) Enable2FA(userID int, secret string, backupCodes []string) error {
    // Store secret and hashed backup codes in database
    return p.db.Exec("UPDATE users SET totp_secret = ?, backup_codes = ? WHERE id = ?", 
        secret, hashCodes(backupCodes), userID).Error
}

func (p *DBTwoFactorProvider) Get2FASecret(userID int) (string, error) {
    var secret string
    err := p.db.Raw("SELECT totp_secret FROM users WHERE id = ?", userID).Scan(&secret).Error
    return secret, err
}

// Implement remaining methods: Generate2FASecret, Validate2FACode, Disable2FA,
// Get2FAStatus, GenerateBackupCodes, ValidateBackupCode
Configuration
config := &security.TwoFactorConfig{
    Algorithm:  "SHA256",  // SHA1, SHA256, SHA512
    Digits:     8,         // 6 or 8
    Period:     30,        // Seconds per code
    SkewWindow: 2,         // Accept codes ±2 periods
}

totp := security.NewTOTPGenerator(config)
tfaAuth := security.NewTwoFactorAuthenticator(baseAuth, tfaProvider, config)
API Response Structure
// LoginResponse with 2FA
type LoginResponse struct {
    Token              string              `json:"token"`
    Requires2FA        bool                `json:"requires_2fa"`
    TwoFactorSetupData *TwoFactorSecret    `json:"two_factor_setup,omitempty"`
    User               *UserContext        `json:"user"`
}

// TwoFactorSecret for setup
type TwoFactorSecret struct {
    Secret      string   `json:"secret"`         // Base32 encoded
    QRCodeURL   string   `json:"qr_code_url"`    // otpauth://totp/...
    BackupCodes []string `json:"backup_codes"`   // 10 recovery codes
}

// UserContext includes 2FA status
type UserContext struct {
    UserID           int    `json:"user_id"`
    TwoFactorEnabled bool   `json:"two_factor_enabled"`
    // ... other fields
}
Security Best Practices
  • Store secrets encrypted - Never store TOTP secrets in plain text

  • Hash backup codes - Use SHA-256 before storing

  • Rate limit - Limit 2FA verification attempts

  • Require password - Always verify password before disabling 2FA

  • Show backup codes once - Display only during setup/regeneration

  • Log 2FA events - Track enable/disable/failed attempts

  • Mark codes as used - Backup codes are single-use only

          json.NewEncoder(w).Encode(resp)
      } else {
          http.Error(w, "Refresh not supported", http.StatusNotImplemented)
      }
    

    } }


### Example 2: Config-Based Security (No Database)

```go
func main() {
    db := setupDatabase()
    handler := restheadspec.NewHandlerWithGORM(db)

    // Static column security rules
    columnRules := map[string][]security.ColumnSecurity{
        "public.employees": {
            {Path: []string{"ssn"}, Accesstype: "mask", MaskStart: 5},
            {Path: []string{"salary"}, Accesstype: "hide"},
        },
    }

    // Static row security templates
    rowTemplates := map[string]string{
        "public.orders": "user_id = {UserID}",
    }

    // Create providers
    auth := security.NewHeaderAuthenticator()
    colSec := security.NewConfigColumnSecurityProvider(columnRules)
    rowSec := security.NewConfigRowSecurityProvider(rowTemplates, nil)

    // Combine providers and register hooks
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)
    restheadspec.RegisterSecurityHooks(handler, securityList)

    // Setup routes...
}
Example 3: FuncSpec Security (SQL Query API)
import (
    "github.com/bitechdev/ResolveSpec/pkg/funcspec"
    "github.com/bitechdev/ResolveSpec/pkg/security"
)

func main() {
    db := setupDatabase()

    // Create funcspec handler
    handler := funcspec.NewHandler(db)

    // Create security providers
    auth := security.NewJWTAuthenticator("secret-key", db)
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks (audit logging)
    funcspec.RegisterSecurityHooks(handler, securityList)

    // Note: funcspec operates on raw SQL queries, so row/column
    // security is limited. Security should be enforced at the
    // SQL function level or via database policies.

    // Setup routes...
}
Example 4: ResolveSpec Security (REST API)
import (
    "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
    "github.com/bitechdev/ResolveSpec/pkg/security"
)

func main() {
    db := setupDatabase()
    registry := common.NewModelRegistry()

    // Register models
    registry.RegisterModel("public.users", &User{})
    registry.RegisterModel("public.orders", &Order{})

    // Create resolvespec handler
    handler := resolvespec.NewHandler(db, registry)

    // Create security providers
    auth := security.NewDatabaseAuthenticator(db)
    colSec := security.NewDatabaseColumnSecurityProvider(db)
    rowSec := security.NewDatabaseRowSecurityProvider(db)

    // Combine providers
    provider := security.NewCompositeSecurityProvider(auth, colSec, rowSec)
    securityList := security.NewSecurityList(provider)

    // Register security hooks for resolvespec
    resolvespec.RegisterSecurityHooks(handler, securityList)

    // Setup routes...
}
Example 5: Custom Provider

Implement your own provider for complete control:

type MySecurityProvider struct {
    db *gorm.DB
}

func (p *MySecurityProvider) Login(ctx context.Context, req security.LoginRequest) (*security.LoginResponse, error) {
    // Your custom login logic
}

func (p *MySecurityProvider) Logout(ctx context.Context, req security.LogoutRequest) error {
    // Your custom logout logic
}

func (p *MySecurityProvider) Authenticate(r *http.Request) (*security.UserContext, error) {
    // Your custom authentication logic
}

func (p *MySecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    // Your custom column security logic
}

func (p *MySecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    // Your custom row security logic
}

// Use it with any spec
provider := &MySecurityProvider{db: db}
securityList := security.NewSecurityList(provider)

// Register with restheadspec
restheadspec.RegisterSecurityHooks(restHandler, securityList)

// Or with funcspec
funcspec.RegisterSecurityHooks(funcHandler, securityList)

// Or with resolvespec
resolvespec.RegisterSecurityHooks(resolveHandler, securityList)

Security Features

Column Security (Masking/Hiding)

Mask SSN (show last 4 digits):

{
    Path:       []string{"ssn"},
    Accesstype: "mask",
    MaskStart:  5,
    MaskChar:   "*",
}
// "123-45-6789" → "*****6789"

Hide entire field:

{
    Path:       []string{"salary"},
    Accesstype: "hide",
}
// Field returns 0 or empty

Nested JSON field masking:

{
    Path:       []string{"address", "street"},
    Accesstype: "mask",
    MaskStart:  10,
}
Row Security (Filtering)

User isolation:

{
    Template: "user_id = {UserID}",
}
// Users only see their own records

Tenant isolation:

{
    Template: "tenant_id = {TenantID} AND user_id = {UserID}",
}

Block all access:

{
    HasBlock: true,
}
// Completely blocks access to the table

Template variables:

  • {UserID} - Current user's ID
  • {PrimaryKeyName} - Primary key column
  • {TableName} - Table name
  • {SchemaName} - Schema name

Request Flow

HTTP Request
    ↓
NewAuthMiddleware (security package)
    ├─ Calls provider.Authenticate(request)
    └─ Adds UserContext to context
    ↓
SetSecurityMiddleware (security package)
    └─ Adds SecurityList to context
    ↓
Spec Handler (restheadspec/funcspec/resolvespec)
    ↓
BeforeRead Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.LoadSecurityRules(secCtx, securityList)
    │   ├─ Calls provider.GetColumnSecurity()
    │   └─ Calls provider.GetRowSecurity()
    └─ Caches security rules
    ↓
BeforeScan Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.ApplyRowSecurity(secCtx, securityList)
    └─ Applies row security (adds WHERE clause to query)
    ↓
Database Query (with security filters)
    ↓
AfterRead Hook (registered by spec)
    ├─ Adapts spec's HookContext → SecurityContext
    ├─ Calls security.ApplyColumnSecurity(secCtx, securityList)
    ├─ Applies column security (masks/hides fields)
    └─ Calls security.LogDataAccess(secCtx)
    ↓
HTTP Response (secured data)

Key Points:

  • Security package is spec-agnostic and provides core logic
  • Each spec registers its own hooks that adapt to SecurityContext
  • Security rules are loaded once and cached for the request
  • Row security is applied to the query (database level)
  • Column security is applied to results (application level)

Testing

The interface-based design makes testing straightforward:

// Mock authenticator for tests
type MockAuthenticator struct {
    UserToReturn *security.UserContext
    ErrorToReturn error
}

func (m *MockAuthenticator) Authenticate(r *http.Request) (*security.UserContext, error) {
    return m.UserToReturn, m.ErrorToReturn
}

// Use in tests
func TestMyHandler(t *testing.T) {
    mockAuth := &MockAuthenticator{
        UserToReturn: &security.UserContext{UserID: 123},
    }

    provider := security.NewCompositeSecurityProvider(
        mockAuth,
        &MockColumnSecurity{},
        &MockRowSecurity{},
    )

    securityList := security.SetupSecurityProvider(handler, provider)
    // ... test your handler
}

Migration Guide

From Old Callback System

If you're upgrading from the old callback-based system:

Old:

security.GlobalSecurity.AuthenticateCallback = myAuthFunc
security.GlobalSecurity.LoadColumnSecurityCallback = myColSecFunc
security.GlobalSecurity.LoadRowSecurityCallback = myRowSecFunc
security.SetupSecurityProvider(handler, &security.GlobalSecurity)

New:

// 1. Wrap your functions in a provider
type MyProvider struct{}

func (p *MyProvider) Authenticate(r *http.Request) (*security.UserContext, error) {
    userID, roles, err := myAuthFunc(r)
    return &security.UserContext{UserID: userID, Roles: strings.Split(roles, ",")}, err
}

func (p *MyProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    return myColSecFunc(userID, schema, table)
}

func (p *MyProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    return myRowSecFunc(userID, schema, table)
}

func (p *MyProvider) Login(ctx context.Context, req security.LoginRequest) (*security.LoginResponse, error) {
    return nil, fmt.Errorf("not implemented")
}

func (p *MyProvider) Logout(ctx context.Context, req security.LogoutRequest) error {
    return nil
}

// 2. Create security list and register hooks
provider := &MyProvider{}
securityList := security.NewSecurityList(provider)

// 3. Register with your spec
restheadspec.RegisterSecurityHooks(handler, securityList)
From Old SetupSecurityProvider API

If you're upgrading from the previous interface-based system:

Old:

securityList := security.SetupSecurityProvider(handler, provider)

New:

securityList := security.NewSecurityList(provider)
restheadspec.RegisterSecurityHooks(handler, securityList) // or funcspec/resolvespec

The main changes:

  1. Security package no longer knows about specific spec types
  2. Each spec registers its own security hooks
  3. More flexible - same security provider works with all specs

Documentation

File Description
QUICK_REFERENCE.md Quick reference guide with examples
INTERFACE_GUIDE.md Complete implementation guide
examples.go Working provider implementations
setup_example.go 6 complete integration examples

API Reference

Context Helpers

Get user information from request context:

userCtx, ok := security.GetUserContext(ctx)
userID, ok := security.GetUserID(ctx)
userName, ok := security.GetUserName(ctx)
userLevel, ok := security.GetUserLevel(ctx)
sessionID, ok := security.GetSessionID(ctx)
remoteID, ok := security.GetRemoteID(ctx)
roles, ok := security.GetUserRoles(ctx)
email, ok := security.GetUserEmail(ctx)
Optional Interfaces

Implement these for additional features:

Refreshable - Token refresh support:

type Refreshable interface {
    RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)
}

Validatable - Token validation:

type Validatable interface {
    ValidateToken(ctx context.Context, token string) (bool, error)
}

Cacheable - Cache management:

type Cacheable interface {
    ClearCache(ctx context.Context, userID int, schema, table string) error
}

Benefits Over Callbacks

Feature Old (Callbacks) New (Interfaces)
Type Safety ❌ Callbacks can be nil ✅ Compile-time verification
Global State ❌ GlobalSecurity variable ✅ Dependency injection
Testability ⚠️ Need to set globals ✅ Easy to mock
Composability ❌ Single provider only ✅ Mix and match
Login/Logout ❌ Not supported ✅ Built-in
Extensibility ⚠️ Limited ✅ Optional interfaces

Common Patterns

Caching Security Rules
type CachedProvider struct {
    inner security.ColumnSecurityProvider
    cache *cache.Cache
}

func (p *CachedProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    key := fmt.Sprintf("%d:%s.%s", userID, schema, table)
    if cached, found := p.cache.Get(key); found {
        return cached.([]security.ColumnSecurity), nil
    }

    rules, err := p.inner.GetColumnSecurity(ctx, userID, schema, table)
    if err == nil {
        p.cache.Set(key, rules, cache.DefaultExpiration)
    }
    return rules, err
}
Role-Based Security
func (p *MyProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]security.ColumnSecurity, error) {
    userCtx, _ := security.GetUserContext(ctx)

    if contains(userCtx.Roles, "admin") {
        return []security.ColumnSecurity{}, nil // No restrictions
    }

    return loadRestrictionsForUser(userID, schema, table), nil
}
Multi-Tenant Isolation
func (p *MyProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (security.RowSecurity, error) {
    tenantID := getUserTenant(userID)

    return security.RowSecurity{
        Template: fmt.Sprintf("tenant_id = %d AND user_id = {UserID}", tenantID),
    }, nil
}

Middleware and Handler API

NewAuthMiddleware

Standard middleware that authenticates all requests:

router.Use(security.NewAuthMiddleware(securityList))

Routes can skip authentication using the SkipAuth helper:

func PublicHandler(w http.ResponseWriter, r *http.Request) {
    ctx := security.SkipAuth(r.Context())
    // This route will bypass authentication
    // A guest user context will be set instead
}

router.Handle("/public", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := security.SkipAuth(r.Context())
    PublicHandler(w, r.WithContext(ctx))
}))

When authentication is skipped, a guest user context is automatically set:

  • UserID: 0
  • UserName: "guest"
  • Roles: ["guest"]
  • RemoteID: Request's remote address

Routes can use optional authentication with the OptionalAuth helper:

func OptionalAuthHandler(w http.ResponseWriter, r *http.Request) {
    ctx := security.OptionalAuth(r.Context())
    r = r.WithContext(ctx)

    // This route will try to authenticate
    // If authentication succeeds, authenticated user context is set
    // If authentication fails, guest user context is set instead

    userCtx, _ := security.GetUserContext(r.Context())
    if userCtx.UserID == 0 {
        // Guest user
        fmt.Fprintf(w, "Welcome, guest!")
    } else {
        // Authenticated user
        fmt.Fprintf(w, "Welcome back, %s!", userCtx.UserName)
    }
}

router.Handle("/home", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := security.OptionalAuth(r.Context())
    OptionalAuthHandler(w, r.WithContext(ctx))
}))

Authentication Modes Summary:

  • Required (default): Authentication must succeed or returns 401
  • SkipAuth: Bypasses authentication entirely, always sets guest context
  • OptionalAuth: Tries authentication, falls back to guest context if it fails
NewAuthHandler

Standalone authentication handler (without middleware wrapping):

// Use when you need authentication logic without middleware
authHandler := security.NewAuthHandler(securityList, myHandler)
http.Handle("/api/protected", authHandler)
NewOptionalAuthHandler

Standalone optional authentication handler that tries to authenticate but falls back to guest:

// Use for routes that should work for both authenticated and guest users
optionalHandler := security.NewOptionalAuthHandler(securityList, myHandler)
http.Handle("/home", optionalHandler)

// Example handler that checks user context
func myHandler(w http.ResponseWriter, r *http.Request) {
    userCtx, _ := security.GetUserContext(r.Context())
    if userCtx.UserID == 0 {
        fmt.Fprintf(w, "Welcome, guest!")
    } else {
        fmt.Fprintf(w, "Welcome back, %s!", userCtx.UserName)
    }
}
Helper Functions

Extract user information from context:

// Get full user context
userCtx, ok := security.GetUserContext(ctx)

// Get specific fields
userID, ok := security.GetUserID(ctx)
userName, ok := security.GetUserName(ctx)
userLevel, ok := security.GetUserLevel(ctx)
sessionID, ok := security.GetSessionID(ctx)
remoteID, ok := security.GetRemoteID(ctx)
roles, ok := security.GetUserRoles(ctx)
email, ok := security.GetUserEmail(ctx)
meta, ok := security.GetUserMeta(ctx)
Metadata Support

The Meta field in UserContext can hold any JSON-serializable values:

// Set metadata during login
loginReq := security.LoginRequest{
    Username: "user@example.com",
    Password: "password",
    Meta: map[string]any{
        "department": "engineering",
        "location": "US",
        "preferences": map[string]any{
            "theme": "dark",
        },
    },
}

// Access metadata in handlers
meta, ok := security.GetUserMeta(ctx)
if ok {
    department := meta["department"].(string)
}

License

Part of the ResolveSpec project.

Documentation

Index

Constants

View Source
const (
	// Context keys for user information
	UserIDKey       contextKey = "user_id"
	UserNameKey     contextKey = "user_name"
	UserLevelKey    contextKey = "user_level"
	SessionIDKey    contextKey = "session_id"
	SessionRIDKey   contextKey = "session_rid"
	RemoteIDKey     contextKey = "remote_id"
	UserRolesKey    contextKey = "user_roles"
	UserEmailKey    contextKey = "user_email"
	UserContextKey  contextKey = "user_context"
	UserMetaKey     contextKey = "user_meta"
	SkipAuthKey     contextKey = "skip_auth"
	OptionalAuthKey contextKey = "optional_auth"
)

Variables

This section is empty.

Functions

func ApplyColumnSecurity added in v0.0.63

func ApplyColumnSecurity(secCtx SecurityContext, securityList *SecurityList) error

ApplyColumnSecurity is a public wrapper for applyColumnSecurity that accepts a SecurityContext This allows other packages to apply column-level security using the generic interface

func ApplyRowSecurity added in v0.0.63

func ApplyRowSecurity(secCtx SecurityContext, securityList *SecurityList) error

ApplyRowSecurity is a public wrapper for applyRowSecurity that accepts a SecurityContext This allows other packages to apply row-level security using the generic interface

func ExampleOAuth2AllProviders added in v1.0.48

func ExampleOAuth2AllProviders()

Example: All OAuth2 Providers at Once

func ExampleOAuth2Complete added in v1.0.48

func ExampleOAuth2Complete()

Example: Complete OAuth2 Integration with Database Setup

func ExampleOAuth2Custom added in v1.0.48

func ExampleOAuth2Custom()

Example: Custom OAuth2 Provider

func ExampleOAuth2GitHub added in v1.0.48

func ExampleOAuth2GitHub()

Example: OAuth2 Authentication with GitHub

func ExampleOAuth2Google added in v1.0.48

func ExampleOAuth2Google()

Example: OAuth2 Authentication with Google

func ExampleOAuth2Logout added in v1.0.48

func ExampleOAuth2Logout()

Example: OAuth2 Logout

func ExampleOAuth2MultiProvider added in v1.0.48

func ExampleOAuth2MultiProvider()

Example: Multi-Provider OAuth2 with Security Integration

func ExampleOAuth2TokenRefresh added in v1.0.48

func ExampleOAuth2TokenRefresh()

Example: OAuth2 with Token Refresh

func GenerateBackupCodes added in v1.0.48

func GenerateBackupCodes(count int) ([]string, error)

GenerateBackupCodes creates random backup codes

func GetRemoteID added in v0.0.63

func GetRemoteID(ctx context.Context) (string, bool)

GetRemoteID extracts the remote ID from context

func GetSessionID added in v0.0.63

func GetSessionID(ctx context.Context) (string, bool)

GetSessionID extracts the session ID from context

func GetSessionRID added in v0.0.81

func GetSessionRID(ctx context.Context) (int64, bool)

GetSessionID extracts the session ID from context

func GetUserEmail added in v0.0.63

func GetUserEmail(ctx context.Context) (string, bool)

GetUserEmail extracts user email from context

func GetUserID

func GetUserID(ctx context.Context) (int, bool)

GetUserID extracts the user ID from context

func GetUserLevel added in v0.0.63

func GetUserLevel(ctx context.Context) (int, bool)

GetUserLevel extracts the user level from context

func GetUserMeta added in v0.0.64

func GetUserMeta(ctx context.Context) (map[string]any, bool)

GetUserMeta extracts user metadata from context

func GetUserName added in v0.0.63

func GetUserName(ctx context.Context) (string, bool)

GetUserName extracts the user name from context

func GetUserRoles

func GetUserRoles(ctx context.Context) ([]string, bool)

GetUserRoles extracts user roles from context

func LoadSecurityRules added in v0.0.63

func LoadSecurityRules(secCtx SecurityContext, securityList *SecurityList) error

LoadSecurityRules is a public wrapper for loadSecurityRules that accepts a SecurityContext This allows other packages to load security rules using the generic interface

func LogDataAccess added in v0.0.63

func LogDataAccess(secCtx SecurityContext) error

LogDataAccess is a public wrapper for logDataAccess that accepts a SecurityContext This allows other packages to use the audit logging functionality

func NewAuthHandler added in v0.0.64

func NewAuthHandler(securityList *SecurityList, next http.Handler) http.Handler

NewAuthHandler creates an authentication handler that can be used standalone This handler performs authentication and returns 401 if authentication fails Use this when you need authentication logic without middleware wrapping

func NewAuthMiddleware added in v0.0.63

func NewAuthMiddleware(securityList *SecurityList) func(http.Handler) http.Handler

NewAuthMiddleware creates an authentication middleware with the given security list This middleware extracts user authentication from the request and adds it to context Routes can skip authentication by setting SkipAuthKey context value (use SkipAuth helper) Routes can use optional authentication by setting OptionalAuthKey context value (use OptionalAuth helper) When authentication is skipped or fails with optional auth, a guest user context is set instead

func NewOptionalAuthHandler added in v0.0.64

func NewOptionalAuthHandler(securityList *SecurityList, next http.Handler) http.Handler

NewOptionalAuthHandler creates an optional authentication handler that can be used standalone This handler tries to authenticate but falls back to guest context if authentication fails Use this for routes that should show personalized content for authenticated users but still work for guests

func OptionalAuth added in v0.0.64

func OptionalAuth(ctx context.Context) context.Context

OptionalAuth returns a context with optional auth flag set to true Use this to mark routes that should try to authenticate, but fall back to guest if authentication fails

func PasskeyAuthenticationExample added in v1.0.48

func PasskeyAuthenticationExample()

PasskeyAuthenticationExample demonstrates passkey (WebAuthn/FIDO2) authentication

func PasskeyClientSideExample added in v1.0.48

func PasskeyClientSideExample() string

PasskeyClientSideExample shows the client-side JavaScript code needed

func PasskeyHTTPHandlersExample added in v1.0.48

func PasskeyHTTPHandlersExample(auth *DatabaseAuthenticator)

PasskeyHTTPHandlersExample shows HTTP handlers for passkey authentication

func SetSecurityMiddleware

func SetSecurityMiddleware(securityList *SecurityList) func(http.Handler) http.Handler

SetSecurityMiddleware adds security context to requests This middleware should be applied after AuthMiddleware

func SkipAuth added in v0.0.64

func SkipAuth(ctx context.Context) context.Context

SkipAuth returns a context with skip auth flag set to true Use this to mark routes that should bypass authentication middleware

func WithAuth added in v0.0.83

func WithAuth(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithAuth wraps an HTTPFuncType handler with required authentication This function performs authentication and returns 401 if authentication fails Use this for handlers that require authenticated users

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithAuth(handler.SqlQueryList("SELECT * FROM orders WHERE user_id = [rid_user]", false, false, false), securityList)
router.HandleFunc("/api/orders", wrappedHandler)

func WithAuthAndSecurity added in v0.0.83

func WithAuthAndSecurity(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithAuthAndSecurity wraps an HTTPFuncType handler with both authentication and security context This is a convenience function that combines WithAuth and WithSecurityContext Use this when you need both authentication and security context for a handler

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithAuthAndSecurity(handler.SqlQueryList("SELECT * FROM users", false, false, false), securityList)
router.HandleFunc("/api/users", wrappedHandler)

func WithOptionalAuth added in v0.0.83

func WithOptionalAuth(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithOptionalAuth wraps an HTTPFuncType handler with optional authentication This function tries to authenticate but falls back to guest context if authentication fails Use this for handlers that should show personalized content for authenticated users but still work for guests

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithOptionalAuth(handler.SqlQueryList("SELECT * FROM products", false, false, false), securityList)
router.HandleFunc("/api/products", wrappedHandler)

func WithOptionalAuthAndSecurity added in v0.0.83

func WithOptionalAuthAndSecurity(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithOptionalAuthAndSecurity wraps an HTTPFuncType handler with optional authentication and security context This is a convenience function that combines WithOptionalAuth and WithSecurityContext Use this when you want optional authentication and security context for a handler

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithOptionalAuthAndSecurity(handler.SqlQueryList("SELECT * FROM products", false, false, false), securityList)
router.HandleFunc("/api/products", wrappedHandler)

func WithSecurityContext added in v0.0.83

func WithSecurityContext(handler func(http.ResponseWriter, *http.Request), securityList *SecurityList) func(http.ResponseWriter, *http.Request)

WithSecurityContext wraps an HTTPFuncType handler with security context This function allows you to add security context to specific handler functions without needing to apply middleware globally

Usage:

handler := funcspec.NewHandler(db)
wrappedHandler := security.WithSecurityContext(handler.SqlQueryList("SELECT * FROM users", false, false, false), securityList)
router.HandleFunc("/api/users", wrappedHandler)

Types

type Authenticator added in v0.0.63

type Authenticator interface {
	// Login authenticates credentials and returns a token
	Login(ctx context.Context, req LoginRequest) (*LoginResponse, error)

	// Logout invalidates a user's session/token
	Logout(ctx context.Context, req LogoutRequest) error

	// Authenticate extracts and validates user from HTTP request
	// Returns UserContext or error if authentication fails
	Authenticate(r *http.Request) (*UserContext, error)
}

Authenticator handles user authentication operations

type CONTEXT_KEY added in v0.0.20

type CONTEXT_KEY string
const SECURITY_CONTEXT_KEY CONTEXT_KEY = "SecurityList"

type Cacheable added in v0.0.63

type Cacheable interface {
	// ClearCache clears cached security rules for a user/entity
	ClearCache(ctx context.Context, userID int, schema, table string) error
}

Cacheable allows providers to support caching of security rules

type ColumnSecurity

type ColumnSecurity struct {
	Schema       string            `json:"schema"`
	Tablename    string            `json:"tablename"`
	Path         []string          `json:"path"`
	ExtraFilters map[string]string `json:"extra_filters"`
	UserID       int               `json:"user_id"`
	Accesstype   string            `json:"accesstype"`
	MaskStart    int               `json:"mask_start"`
	MaskEnd      int               `json:"mask_end"`
	MaskInvert   bool              `json:"mask_invert"`
	MaskChar     string            `json:"mask_char"`
	Control      string            `json:"control"`
	ID           int               `json:"id"`
}

type ColumnSecurityProvider added in v0.0.63

type ColumnSecurityProvider interface {
	// GetColumnSecurity loads column security rules for a user and entity
	GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)
}

ColumnSecurityProvider handles column-level security (masking/hiding)

type CompositeSecurityProvider added in v0.0.63

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

CompositeSecurityProvider combines multiple security providers Allows separating authentication, column security, and row security concerns

func NewCompositeSecurityProvider added in v0.0.63

func NewCompositeSecurityProvider(
	auth Authenticator,
	colSec ColumnSecurityProvider,
	rowSec RowSecurityProvider,
) (*CompositeSecurityProvider, error)

NewCompositeSecurityProvider creates a composite provider All parameters are required

func (*CompositeSecurityProvider) Authenticate added in v0.0.63

func (c *CompositeSecurityProvider) Authenticate(r *http.Request) (*UserContext, error)

Authenticate delegates to the authenticator

func (*CompositeSecurityProvider) ClearCache added in v0.0.63

func (c *CompositeSecurityProvider) ClearCache(ctx context.Context, userID int, schema, table string) error

ClearCache implements Cacheable if any provider supports it

func (*CompositeSecurityProvider) GetColumnSecurity added in v0.0.63

func (c *CompositeSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

GetColumnSecurity delegates to the column security provider

func (*CompositeSecurityProvider) GetRowSecurity added in v0.0.63

func (c *CompositeSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

GetRowSecurity delegates to the row security provider

func (*CompositeSecurityProvider) Login added in v0.0.63

Login delegates to the authenticator

func (*CompositeSecurityProvider) Logout added in v0.0.63

Logout delegates to the authenticator

func (*CompositeSecurityProvider) RefreshToken added in v0.0.63

func (c *CompositeSecurityProvider) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

RefreshToken implements Refreshable if the authenticator supports it

func (*CompositeSecurityProvider) ValidateToken added in v0.0.63

func (c *CompositeSecurityProvider) ValidateToken(ctx context.Context, token string) (bool, error)

ValidateToken implements Validatable if the authenticator supports it

type ConfigColumnSecurityProvider added in v0.0.63

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

ConfigColumnSecurityProvider provides static column security configuration

func NewConfigColumnSecurityProvider added in v0.0.63

func NewConfigColumnSecurityProvider(rules map[string][]ColumnSecurity) *ConfigColumnSecurityProvider

func (*ConfigColumnSecurityProvider) GetColumnSecurity added in v0.0.63

func (p *ConfigColumnSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

type ConfigRowSecurityProvider added in v0.0.63

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

ConfigRowSecurityProvider provides static row security configuration

func NewConfigRowSecurityProvider added in v0.0.63

func NewConfigRowSecurityProvider(templates map[string]string, blocked map[string]bool) *ConfigRowSecurityProvider

func (*ConfigRowSecurityProvider) GetRowSecurity added in v0.0.63

func (p *ConfigRowSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

type DatabaseAuthenticator added in v0.0.63

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

DatabaseAuthenticator provides session-based authentication with database storage All database operations go through stored procedures for security and consistency Requires stored procedures: resolvespec_login, resolvespec_logout, resolvespec_session, resolvespec_session_update, resolvespec_refresh_token See database_schema.sql for procedure definitions Also supports multiple OAuth2 providers configured with WithOAuth2() Also supports passkey authentication configured with WithPasskey()

func NewDatabaseAuthenticator added in v0.0.63

func NewDatabaseAuthenticator(db *sql.DB) *DatabaseAuthenticator

func NewDatabaseAuthenticatorWithOptions added in v0.0.86

func NewDatabaseAuthenticatorWithOptions(db *sql.DB, opts DatabaseAuthenticatorOptions) *DatabaseAuthenticator

func NewFacebookAuthenticator added in v1.0.48

func NewFacebookAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator

NewFacebookAuthenticator creates a DatabaseAuthenticator configured for Facebook OAuth2

func NewGitHubAuthenticator added in v1.0.48

func NewGitHubAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator

NewGitHubAuthenticator creates a DatabaseAuthenticator configured for GitHub OAuth2

func NewGoogleAuthenticator added in v1.0.48

func NewGoogleAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator

NewGoogleAuthenticator creates a DatabaseAuthenticator configured for Google OAuth2

func NewMicrosoftAuthenticator added in v1.0.48

func NewMicrosoftAuthenticator(clientID, clientSecret, redirectURL string, db *sql.DB) *DatabaseAuthenticator

NewMicrosoftAuthenticator creates a DatabaseAuthenticator configured for Microsoft OAuth2

func NewMultiProviderAuthenticator added in v1.0.48

func NewMultiProviderAuthenticator(db *sql.DB, configs map[string]OAuth2Config) *DatabaseAuthenticator

NewMultiProviderAuthenticator creates a DatabaseAuthenticator with all major OAuth2 providers configured

func (*DatabaseAuthenticator) Authenticate added in v0.0.63

func (a *DatabaseAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*DatabaseAuthenticator) BeginPasskeyAuthentication added in v1.0.48

BeginPasskeyAuthentication initiates passkey authentication

func (*DatabaseAuthenticator) BeginPasskeyRegistration added in v1.0.48

BeginPasskeyRegistration initiates passkey registration for a user

func (*DatabaseAuthenticator) ClearCache added in v0.0.86

func (a *DatabaseAuthenticator) ClearCache(token string) error

ClearCache removes a specific token from the cache or clears all cache if token is empty

func (*DatabaseAuthenticator) ClearUserCache added in v0.0.86

func (a *DatabaseAuthenticator) ClearUserCache(userID int) error

ClearUserCache removes all cache entries for a specific user ID

func (*DatabaseAuthenticator) CompletePasskeyRegistration added in v1.0.48

func (a *DatabaseAuthenticator) CompletePasskeyRegistration(ctx context.Context, req PasskeyRegisterRequest) (*PasskeyCredential, error)

CompletePasskeyRegistration completes passkey registration

func (*DatabaseAuthenticator) DeletePasskeyCredential added in v1.0.48

func (a *DatabaseAuthenticator) DeletePasskeyCredential(ctx context.Context, userID int, credentialID string) error

DeletePasskeyCredential removes a passkey credential

func (*DatabaseAuthenticator) GetPasskeyCredentials added in v1.0.48

func (a *DatabaseAuthenticator) GetPasskeyCredentials(ctx context.Context, userID int) ([]PasskeyCredential, error)

GetPasskeyCredentials returns all passkey credentials for a user

func (*DatabaseAuthenticator) Login added in v0.0.63

func (*DatabaseAuthenticator) LoginWithPasskey added in v1.0.48

func (a *DatabaseAuthenticator) LoginWithPasskey(ctx context.Context, req PasskeyLoginRequest) (*LoginResponse, error)

LoginWithPasskey authenticates a user using a passkey and creates a session

func (*DatabaseAuthenticator) Logout added in v0.0.63

func (*DatabaseAuthenticator) OAuth2GenerateState added in v1.0.48

func (a *DatabaseAuthenticator) OAuth2GenerateState() (string, error)

OAuth2GenerateState generates a random state string for CSRF protection

func (*DatabaseAuthenticator) OAuth2GetAuthURL added in v1.0.48

func (a *DatabaseAuthenticator) OAuth2GetAuthURL(providerName, state string) (string, error)

OAuth2GetAuthURL returns the OAuth2 authorization URL for redirecting users

func (*DatabaseAuthenticator) OAuth2GetProviders added in v1.0.48

func (a *DatabaseAuthenticator) OAuth2GetProviders() []string

OAuth2GetProviders returns list of configured OAuth2 provider names

func (*DatabaseAuthenticator) OAuth2HandleCallback added in v1.0.48

func (a *DatabaseAuthenticator) OAuth2HandleCallback(ctx context.Context, providerName, code, state string) (*LoginResponse, error)

OAuth2HandleCallback handles the OAuth2 callback and exchanges code for token

func (*DatabaseAuthenticator) OAuth2RefreshToken added in v1.0.48

func (a *DatabaseAuthenticator) OAuth2RefreshToken(ctx context.Context, refreshToken, providerName string) (*LoginResponse, error)

OAuth2RefreshToken refreshes an expired OAuth2 access token using the refresh token Takes the refresh token and returns a new LoginResponse with updated tokens

func (*DatabaseAuthenticator) RefreshToken added in v0.0.63

func (a *DatabaseAuthenticator) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

RefreshToken implements Refreshable interface

func (*DatabaseAuthenticator) Register added in v1.0.48

Register implements Registrable interface

func (*DatabaseAuthenticator) UpdatePasskeyCredentialName added in v1.0.48

func (a *DatabaseAuthenticator) UpdatePasskeyCredentialName(ctx context.Context, userID int, credentialID string, name string) error

UpdatePasskeyCredentialName updates the friendly name of a credential

func (*DatabaseAuthenticator) WithOAuth2 added in v1.0.48

WithOAuth2 configures OAuth2 support for the DatabaseAuthenticator Can be called multiple times to add multiple OAuth2 providers Returns the same DatabaseAuthenticator instance for method chaining

func (*DatabaseAuthenticator) WithPasskey added in v1.0.48

WithPasskey configures the DatabaseAuthenticator with a passkey provider

type DatabaseAuthenticatorExample added in v0.0.63

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

func NewDatabaseAuthenticatorExample added in v0.0.63

func NewDatabaseAuthenticatorExample(db *gorm.DB) *DatabaseAuthenticatorExample

func (*DatabaseAuthenticatorExample) Authenticate added in v0.0.63

func (a *DatabaseAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*DatabaseAuthenticatorExample) Login added in v0.0.63

func (*DatabaseAuthenticatorExample) Logout added in v0.0.63

func (*DatabaseAuthenticatorExample) RefreshToken added in v0.0.63

func (a *DatabaseAuthenticatorExample) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

Optional: Implement Refreshable interface

type DatabaseAuthenticatorOptions added in v0.0.86

type DatabaseAuthenticatorOptions struct {
	// CacheTTL is the duration to cache user contexts
	// Default: 5 minutes
	CacheTTL time.Duration
	// Cache is an optional cache instance. If nil, uses the default cache
	Cache *cache.Cache
	// PasskeyProvider is an optional passkey provider for WebAuthn/FIDO2 authentication
	PasskeyProvider PasskeyProvider
}

DatabaseAuthenticatorOptions configures the database authenticator

type DatabaseColumnSecurityProvider added in v0.0.63

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

DatabaseColumnSecurityProvider loads column security from database All database operations go through stored procedures Requires stored procedure: resolvespec_column_security

func NewDatabaseColumnSecurityProvider added in v0.0.63

func NewDatabaseColumnSecurityProvider(db *sql.DB) *DatabaseColumnSecurityProvider

func (*DatabaseColumnSecurityProvider) GetColumnSecurity added in v0.0.63

func (p *DatabaseColumnSecurityProvider) GetColumnSecurity(ctx context.Context, userID int, schema, table string) ([]ColumnSecurity, error)

type DatabasePasskeyProvider added in v1.0.48

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

DatabasePasskeyProvider implements PasskeyProvider using database storage

func NewDatabasePasskeyProvider added in v1.0.48

func NewDatabasePasskeyProvider(db *sql.DB, opts DatabasePasskeyProviderOptions) *DatabasePasskeyProvider

NewDatabasePasskeyProvider creates a new database-backed passkey provider

func (*DatabasePasskeyProvider) BeginAuthentication added in v1.0.48

func (p *DatabasePasskeyProvider) BeginAuthentication(ctx context.Context, username string) (*PasskeyAuthenticationOptions, error)

BeginAuthentication creates authentication options for passkey login

func (*DatabasePasskeyProvider) BeginRegistration added in v1.0.48

func (p *DatabasePasskeyProvider) BeginRegistration(ctx context.Context, userID int, username, displayName string) (*PasskeyRegistrationOptions, error)

BeginRegistration creates registration options for a new passkey

func (*DatabasePasskeyProvider) CompleteAuthentication added in v1.0.48

func (p *DatabasePasskeyProvider) CompleteAuthentication(ctx context.Context, response PasskeyAuthenticationResponse, expectedChallenge []byte) (int, error)

CompleteAuthentication verifies a passkey assertion and returns the user ID NOTE: This is a simplified implementation. In production, you should use a WebAuthn library like github.com/go-webauthn/webauthn to properly verify the assertion signature.

func (*DatabasePasskeyProvider) CompleteRegistration added in v1.0.48

func (p *DatabasePasskeyProvider) CompleteRegistration(ctx context.Context, userID int, response PasskeyRegistrationResponse, expectedChallenge []byte) (*PasskeyCredential, error)

CompleteRegistration verifies and stores a new passkey credential NOTE: This is a simplified implementation. In production, you should use a WebAuthn library like github.com/go-webauthn/webauthn to properly verify attestation and parse credentials.

func (*DatabasePasskeyProvider) DeleteCredential added in v1.0.48

func (p *DatabasePasskeyProvider) DeleteCredential(ctx context.Context, userID int, credentialID string) error

DeleteCredential removes a passkey credential

func (*DatabasePasskeyProvider) GetCredentials added in v1.0.48

func (p *DatabasePasskeyProvider) GetCredentials(ctx context.Context, userID int) ([]PasskeyCredential, error)

GetCredentials returns all passkey credentials for a user

func (*DatabasePasskeyProvider) UpdateCredentialName added in v1.0.48

func (p *DatabasePasskeyProvider) UpdateCredentialName(ctx context.Context, userID int, credentialID string, name string) error

UpdateCredentialName updates the friendly name of a credential

type DatabasePasskeyProviderOptions added in v1.0.48

type DatabasePasskeyProviderOptions struct {
	// RPID is the Relying Party ID (typically your domain, e.g., "example.com")
	RPID string
	// RPName is the display name for your relying party
	RPName string
	// RPOrigin is the expected origin (e.g., "https://example.com")
	RPOrigin string
	// Timeout is the timeout for operations in milliseconds (default: 60000)
	Timeout int64
}

DatabasePasskeyProviderOptions configures the passkey provider

type DatabaseRowSecurityProvider added in v0.0.63

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

DatabaseRowSecurityProvider loads row security from database All database operations go through stored procedures Requires stored procedure: resolvespec_row_security

func NewDatabaseRowSecurityProvider added in v0.0.63

func NewDatabaseRowSecurityProvider(db *sql.DB) *DatabaseRowSecurityProvider

func (*DatabaseRowSecurityProvider) GetRowSecurity added in v0.0.63

func (p *DatabaseRowSecurityProvider) GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)

type DatabaseTwoFactorProvider added in v1.0.48

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

DatabaseTwoFactorProvider implements TwoFactorAuthProvider using PostgreSQL stored procedures Requires stored procedures: resolvespec_totp_enable, resolvespec_totp_disable, resolvespec_totp_get_status, resolvespec_totp_get_secret, resolvespec_totp_regenerate_backup_codes, resolvespec_totp_validate_backup_code See totp_database_schema.sql for procedure definitions

func NewDatabaseTwoFactorProvider added in v1.0.48

func NewDatabaseTwoFactorProvider(db *sql.DB, config *TwoFactorConfig) *DatabaseTwoFactorProvider

NewDatabaseTwoFactorProvider creates a new database-backed 2FA provider

func (*DatabaseTwoFactorProvider) Disable2FA added in v1.0.48

func (p *DatabaseTwoFactorProvider) Disable2FA(userID int) error

Disable2FA deactivates 2FA for a user

func (*DatabaseTwoFactorProvider) Enable2FA added in v1.0.48

func (p *DatabaseTwoFactorProvider) Enable2FA(userID int, secret string, backupCodes []string) error

Enable2FA activates 2FA for a user

func (*DatabaseTwoFactorProvider) Generate2FASecret added in v1.0.48

func (p *DatabaseTwoFactorProvider) Generate2FASecret(userID int, issuer, accountName string) (*TwoFactorSecret, error)

Generate2FASecret creates a new secret for a user

func (*DatabaseTwoFactorProvider) GenerateBackupCodes added in v1.0.48

func (p *DatabaseTwoFactorProvider) GenerateBackupCodes(userID int, count int) ([]string, error)

GenerateBackupCodes creates backup codes for 2FA

func (*DatabaseTwoFactorProvider) Get2FASecret added in v1.0.48

func (p *DatabaseTwoFactorProvider) Get2FASecret(userID int) (string, error)

Get2FASecret retrieves the user's 2FA secret

func (*DatabaseTwoFactorProvider) Get2FAStatus added in v1.0.48

func (p *DatabaseTwoFactorProvider) Get2FAStatus(userID int) (bool, error)

Get2FAStatus checks if user has 2FA enabled

func (*DatabaseTwoFactorProvider) Validate2FACode added in v1.0.48

func (p *DatabaseTwoFactorProvider) Validate2FACode(secret string, code string) (bool, error)

Validate2FACode verifies a TOTP code

func (*DatabaseTwoFactorProvider) ValidateBackupCode added in v1.0.48

func (p *DatabaseTwoFactorProvider) ValidateBackupCode(userID int, code string) (bool, error)

ValidateBackupCode checks and consumes a backup code

type HeaderAuthenticator added in v0.0.63

type HeaderAuthenticator struct{}

HeaderAuthenticator provides simple header-based authentication Expects: X-User-ID, X-User-Name, X-User-Level, X-Session-ID, X-Remote-ID, X-User-Roles, X-User-Email

func NewHeaderAuthenticator added in v0.0.63

func NewHeaderAuthenticator() *HeaderAuthenticator

func (*HeaderAuthenticator) Authenticate added in v0.0.63

func (a *HeaderAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*HeaderAuthenticator) Login added in v0.0.63

func (*HeaderAuthenticator) Logout added in v0.0.63

type HeaderAuthenticatorExample added in v0.0.63

type HeaderAuthenticatorExample struct {
}

func NewHeaderAuthenticatorExample added in v0.0.63

func NewHeaderAuthenticatorExample() *HeaderAuthenticatorExample

func (*HeaderAuthenticatorExample) Authenticate added in v0.0.63

func (a *HeaderAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*HeaderAuthenticatorExample) Login added in v0.0.63

func (*HeaderAuthenticatorExample) Logout added in v0.0.63

type JWTAuthenticator added in v0.0.63

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

JWTAuthenticator provides JWT token-based authentication All database operations go through stored procedures Requires stored procedures: resolvespec_jwt_login, resolvespec_jwt_logout NOTE: JWT signing/verification requires github.com/golang-jwt/jwt/v5 to be installed and imported

func NewJWTAuthenticator added in v0.0.63

func NewJWTAuthenticator(secretKey string, db *sql.DB) *JWTAuthenticator

func (*JWTAuthenticator) Authenticate added in v0.0.63

func (a *JWTAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

func (*JWTAuthenticator) Login added in v0.0.63

func (*JWTAuthenticator) Logout added in v0.0.63

func (a *JWTAuthenticator) Logout(ctx context.Context, req LogoutRequest) error

type JWTAuthenticatorExample added in v0.0.63

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

func NewJWTAuthenticatorExample added in v0.0.63

func NewJWTAuthenticatorExample(secretKey string, db *gorm.DB) *JWTAuthenticatorExample

func (*JWTAuthenticatorExample) Authenticate added in v0.0.63

func (a *JWTAuthenticatorExample) Authenticate(r *http.Request) (*UserContext, error)

func (*JWTAuthenticatorExample) Login added in v0.0.63

func (*JWTAuthenticatorExample) Logout added in v0.0.63

type LoginRequest added in v0.0.63

type LoginRequest struct {
	Username      string         `json:"username"`
	Password      string         `json:"password"`
	TwoFactorCode string         `json:"two_factor_code,omitempty"` // TOTP or backup code
	Claims        map[string]any `json:"claims"`                    // Additional login data
	Meta          map[string]any `json:"meta"`                      // Additional metadata to be set on user context
}

LoginRequest contains credentials for login

type LoginResponse added in v0.0.63

type LoginResponse struct {
	Token              string           `json:"token"`
	RefreshToken       string           `json:"refresh_token"`
	User               *UserContext     `json:"user"`
	ExpiresIn          int64            `json:"expires_in"`                 // Token expiration in seconds
	Requires2FA        bool             `json:"requires_2fa"`               // True if 2FA code is required
	TwoFactorSetupData *TwoFactorSecret `json:"two_factor_setup,omitempty"` // Present when setting up 2FA
	Meta               map[string]any   `json:"meta"`                       // Additional metadata to be set on user context
}

LoginResponse contains the result of a login attempt

type LogoutRequest added in v0.0.63

type LogoutRequest struct {
	Token  string `json:"token"`
	UserID int    `json:"user_id"`
}

LogoutRequest contains information for logout

type MemoryTwoFactorProvider added in v1.0.48

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

MemoryTwoFactorProvider is an in-memory implementation of TwoFactorAuthProvider for testing/examples

func NewMemoryTwoFactorProvider added in v1.0.48

func NewMemoryTwoFactorProvider(config *TwoFactorConfig) *MemoryTwoFactorProvider

NewMemoryTwoFactorProvider creates a new in-memory 2FA provider

func (*MemoryTwoFactorProvider) Disable2FA added in v1.0.48

func (m *MemoryTwoFactorProvider) Disable2FA(userID int) error

Disable2FA deactivates 2FA for a user

func (*MemoryTwoFactorProvider) Enable2FA added in v1.0.48

func (m *MemoryTwoFactorProvider) Enable2FA(userID int, secret string, backupCodes []string) error

Enable2FA activates 2FA for a user

func (*MemoryTwoFactorProvider) Generate2FASecret added in v1.0.48

func (m *MemoryTwoFactorProvider) Generate2FASecret(userID int, issuer, accountName string) (*TwoFactorSecret, error)

Generate2FASecret creates a new secret for a user

func (*MemoryTwoFactorProvider) GenerateBackupCodes added in v1.0.48

func (m *MemoryTwoFactorProvider) GenerateBackupCodes(userID int, count int) ([]string, error)

GenerateBackupCodes creates backup codes for 2FA

func (*MemoryTwoFactorProvider) Get2FASecret added in v1.0.48

func (m *MemoryTwoFactorProvider) Get2FASecret(userID int) (string, error)

Get2FASecret retrieves the user's 2FA secret

func (*MemoryTwoFactorProvider) Get2FAStatus added in v1.0.48

func (m *MemoryTwoFactorProvider) Get2FAStatus(userID int) (bool, error)

Get2FAStatus checks if user has 2FA enabled

func (*MemoryTwoFactorProvider) Validate2FACode added in v1.0.48

func (m *MemoryTwoFactorProvider) Validate2FACode(secret string, code string) (bool, error)

Validate2FACode verifies a TOTP code

func (*MemoryTwoFactorProvider) ValidateBackupCode added in v1.0.48

func (m *MemoryTwoFactorProvider) ValidateBackupCode(userID int, code string) (bool, error)

ValidateBackupCode checks and consumes a backup code

type OAuth2Config added in v1.0.48

type OAuth2Config struct {
	ClientID     string
	ClientSecret string
	RedirectURL  string
	Scopes       []string
	AuthURL      string
	TokenURL     string
	UserInfoURL  string
	ProviderName string

	// Optional: Custom user info parser
	// If not provided, will use standard claims (sub, email, name)
	UserInfoParser func(userInfo map[string]any) (*UserContext, error)
}

OAuth2Config contains configuration for OAuth2 authentication

type OAuth2Provider added in v1.0.48

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

OAuth2Provider holds configuration and state for a single OAuth2 provider

type PasskeyAuthenticationOptions added in v1.0.48

type PasskeyAuthenticationOptions struct {
	Challenge        []byte                        `json:"challenge"`
	Timeout          int64                         `json:"timeout,omitempty"`
	RelyingPartyID   string                        `json:"rpId,omitempty"`
	AllowCredentials []PasskeyCredentialDescriptor `json:"allowCredentials,omitempty"`
	UserVerification string                        `json:"userVerification,omitempty"` // required, preferred, discouraged
	Extensions       map[string]any                `json:"extensions,omitempty"`
}

PasskeyAuthenticationOptions contains options for beginning passkey authentication

type PasskeyAuthenticationResponse added in v1.0.48

type PasskeyAuthenticationResponse struct {
	ID                     string                                `json:"id"`    // Base64URL encoded credential ID
	RawID                  []byte                                `json:"rawId"` // Raw credential ID
	Type                   string                                `json:"type"`  // "public-key"
	Response               PasskeyAuthenticatorAssertionResponse `json:"response"`
	ClientExtensionResults map[string]any                        `json:"clientExtensionResults,omitempty"`
}

PasskeyAuthenticationResponse contains the client's authentication response

func ParsePasskeyAuthenticationResponse added in v1.0.48

func ParsePasskeyAuthenticationResponse(data []byte) (*PasskeyAuthenticationResponse, error)

ParsePasskeyAuthenticationResponse parses a JSON passkey authentication response

type PasskeyAuthenticatorAssertionResponse added in v1.0.48

type PasskeyAuthenticatorAssertionResponse struct {
	ClientDataJSON    []byte `json:"clientDataJSON"`
	AuthenticatorData []byte `json:"authenticatorData"`
	Signature         []byte `json:"signature"`
	UserHandle        []byte `json:"userHandle,omitempty"`
}

PasskeyAuthenticatorAssertionResponse contains assertion data

type PasskeyAuthenticatorAttestationResponse added in v1.0.48

type PasskeyAuthenticatorAttestationResponse struct {
	ClientDataJSON    []byte   `json:"clientDataJSON"`
	AttestationObject []byte   `json:"attestationObject"`
	Transports        []string `json:"transports,omitempty"`
}

PasskeyAuthenticatorAttestationResponse contains attestation data

type PasskeyAuthenticatorSelection added in v1.0.48

type PasskeyAuthenticatorSelection struct {
	AuthenticatorAttachment string `json:"authenticatorAttachment,omitempty"` // platform, cross-platform
	RequireResidentKey      bool   `json:"requireResidentKey,omitempty"`
	ResidentKey             string `json:"residentKey,omitempty"`      // discouraged, preferred, required
	UserVerification        string `json:"userVerification,omitempty"` // required, preferred, discouraged
}

PasskeyAuthenticatorSelection specifies authenticator requirements

type PasskeyBeginAuthenticationRequest added in v1.0.48

type PasskeyBeginAuthenticationRequest struct {
	Username string `json:"username,omitempty"` // Optional for resident key flow
}

PasskeyBeginAuthenticationRequest contains options for starting passkey authentication

type PasskeyBeginRegistrationRequest added in v1.0.48

type PasskeyBeginRegistrationRequest struct {
	UserID      int    `json:"user_id"`
	Username    string `json:"username"`
	DisplayName string `json:"display_name"`
}

PasskeyBeginRegistrationRequest contains options for starting passkey registration

type PasskeyCredential added in v1.0.48

type PasskeyCredential struct {
	ID              string    `json:"id"`
	UserID          int       `json:"user_id"`
	CredentialID    []byte    `json:"credential_id"`        // Raw credential ID from authenticator
	PublicKey       []byte    `json:"public_key"`           // COSE public key
	AttestationType string    `json:"attestation_type"`     // none, indirect, direct
	AAGUID          []byte    `json:"aaguid"`               // Authenticator AAGUID
	SignCount       uint32    `json:"sign_count"`           // Signature counter
	CloneWarning    bool      `json:"clone_warning"`        // True if cloning detected
	Transports      []string  `json:"transports,omitempty"` // usb, nfc, ble, internal
	BackupEligible  bool      `json:"backup_eligible"`      // Credential can be backed up
	BackupState     bool      `json:"backup_state"`         // Credential is currently backed up
	Name            string    `json:"name,omitempty"`       // User-friendly name
	CreatedAt       time.Time `json:"created_at"`
	LastUsedAt      time.Time `json:"last_used_at"`
}

PasskeyCredential represents a stored WebAuthn/FIDO2 credential

type PasskeyCredentialDescriptor added in v1.0.48

type PasskeyCredentialDescriptor struct {
	Type       string   `json:"type"`                 // "public-key"
	ID         []byte   `json:"id"`                   // Credential ID
	Transports []string `json:"transports,omitempty"` // usb, nfc, ble, internal
}

PasskeyCredentialDescriptor describes a credential

type PasskeyCredentialParam added in v1.0.48

type PasskeyCredentialParam struct {
	Type string `json:"type"` // "public-key"
	Alg  int    `json:"alg"`  // COSE algorithm identifier (e.g., -7 for ES256, -257 for RS256)
}

PasskeyCredentialParam specifies supported public key algorithm

type PasskeyLoginRequest added in v1.0.48

type PasskeyLoginRequest struct {
	Response          PasskeyAuthenticationResponse `json:"response"`
	ExpectedChallenge []byte                        `json:"expected_challenge"`
	Claims            map[string]any                `json:"claims"` // Additional login data
}

PasskeyLoginRequest contains passkey authentication data

type PasskeyProvider added in v1.0.48

type PasskeyProvider interface {
	// BeginRegistration creates registration options for a new passkey
	BeginRegistration(ctx context.Context, userID int, username, displayName string) (*PasskeyRegistrationOptions, error)

	// CompleteRegistration verifies and stores a new passkey credential
	CompleteRegistration(ctx context.Context, userID int, response PasskeyRegistrationResponse, expectedChallenge []byte) (*PasskeyCredential, error)

	// BeginAuthentication creates authentication options for passkey login
	BeginAuthentication(ctx context.Context, username string) (*PasskeyAuthenticationOptions, error)

	// CompleteAuthentication verifies a passkey assertion and returns the user
	CompleteAuthentication(ctx context.Context, response PasskeyAuthenticationResponse, expectedChallenge []byte) (int, error)

	// GetCredentials returns all passkey credentials for a user
	GetCredentials(ctx context.Context, userID int) ([]PasskeyCredential, error)

	// DeleteCredential removes a passkey credential
	DeleteCredential(ctx context.Context, userID int, credentialID string) error

	// UpdateCredentialName updates the friendly name of a credential
	UpdateCredentialName(ctx context.Context, userID int, credentialID string, name string) error
}

PasskeyProvider handles passkey registration and authentication

type PasskeyRegisterRequest added in v1.0.48

type PasskeyRegisterRequest struct {
	UserID            int                         `json:"user_id"`
	Response          PasskeyRegistrationResponse `json:"response"`
	ExpectedChallenge []byte                      `json:"expected_challenge"`
	CredentialName    string                      `json:"credential_name,omitempty"`
}

PasskeyRegisterRequest contains passkey registration data

type PasskeyRegistrationOptions added in v1.0.48

type PasskeyRegistrationOptions struct {
	Challenge              []byte                         `json:"challenge"`
	RelyingParty           PasskeyRelyingParty            `json:"rp"`
	User                   PasskeyUser                    `json:"user"`
	PubKeyCredParams       []PasskeyCredentialParam       `json:"pubKeyCredParams"`
	Timeout                int64                          `json:"timeout,omitempty"` // Milliseconds
	ExcludeCredentials     []PasskeyCredentialDescriptor  `json:"excludeCredentials,omitempty"`
	AuthenticatorSelection *PasskeyAuthenticatorSelection `json:"authenticatorSelection,omitempty"`
	Attestation            string                         `json:"attestation,omitempty"` // none, indirect, direct, enterprise
	Extensions             map[string]any                 `json:"extensions,omitempty"`
}

PasskeyRegistrationOptions contains options for beginning passkey registration

type PasskeyRegistrationResponse added in v1.0.48

type PasskeyRegistrationResponse struct {
	ID                     string                                  `json:"id"`    // Base64URL encoded credential ID
	RawID                  []byte                                  `json:"rawId"` // Raw credential ID
	Type                   string                                  `json:"type"`  // "public-key"
	Response               PasskeyAuthenticatorAttestationResponse `json:"response"`
	ClientExtensionResults map[string]any                          `json:"clientExtensionResults,omitempty"`
	Transports             []string                                `json:"transports,omitempty"`
}

PasskeyRegistrationResponse contains the client's registration response

func ParsePasskeyRegistrationResponse added in v1.0.48

func ParsePasskeyRegistrationResponse(data []byte) (*PasskeyRegistrationResponse, error)

ParsePasskeyRegistrationResponse parses a JSON passkey registration response

type PasskeyRelyingParty added in v1.0.48

type PasskeyRelyingParty struct {
	ID   string `json:"id"`   // Domain (e.g., "example.com")
	Name string `json:"name"` // Display name
}

PasskeyRelyingParty identifies the relying party

type PasskeyUser added in v1.0.48

type PasskeyUser struct {
	ID          []byte `json:"id"`          // User handle (unique, persistent)
	Name        string `json:"name"`        // Username
	DisplayName string `json:"displayName"` // Display name
}

PasskeyUser identifies the user

type Refreshable added in v0.0.63

type Refreshable interface {
	// RefreshToken exchanges a refresh token for a new access token
	RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)
}

Refreshable allows providers to support token refresh

type RegisterRequest added in v1.0.48

type RegisterRequest struct {
	Username  string         `json:"username"`
	Password  string         `json:"password"`
	Email     string         `json:"email"`
	UserLevel int            `json:"user_level"`
	Roles     []string       `json:"roles"`
	Claims    map[string]any `json:"claims"` // Additional registration data
	Meta      map[string]any `json:"meta"`   // Additional metadata
}

RegisterRequest contains information for new user registration

type Registrable added in v1.0.48

type Registrable interface {
	// Register creates a new user account
	Register(ctx context.Context, req RegisterRequest) (*LoginResponse, error)
}

Registrable allows providers to support user registration

type RowSecurity

type RowSecurity struct {
	Schema    string `json:"schema"`
	Tablename string `json:"tablename"`
	Template  string `json:"template"`
	HasBlock  bool   `json:"has_block"`
	UserID    int    `json:"user_id"`
}

func (*RowSecurity) GetTemplate

func (m *RowSecurity) GetTemplate(pPrimaryKeyName string, pModelType reflect.Type) string

type RowSecurityProvider added in v0.0.63

type RowSecurityProvider interface {
	// GetRowSecurity loads row security rules for a user and entity
	GetRowSecurity(ctx context.Context, userID int, schema, table string) (RowSecurity, error)
}

RowSecurityProvider handles row-level security (filtering)

type SecurityContext added in v0.0.67

type SecurityContext interface {
	GetContext() context.Context
	GetUserID() (int, bool)
	GetSchema() string
	GetEntity() string
	GetModel() interface{}
	GetQuery() interface{}
	SetQuery(interface{})
	GetResult() interface{}
	SetResult(interface{})
}

SecurityContext is a generic interface that any spec can implement to integrate with security features This interface abstracts the common security context needs across different specs

type SecurityList

type SecurityList struct {
	ColumnSecurityMutex sync.RWMutex
	ColumnSecurity      map[string][]ColumnSecurity
	RowSecurityMutex    sync.RWMutex
	RowSecurity         map[string]RowSecurity
	// contains filtered or unexported fields
}

SecurityList manages security state and caching It wraps a SecurityProvider and provides caching and utility methods

func GetSecurityList added in v0.0.83

func GetSecurityList(ctx context.Context) (*SecurityList, bool)

GetSecurityList extracts the SecurityList from request context

func NewSecurityList added in v0.0.63

func NewSecurityList(provider SecurityProvider) (*SecurityList, error)

NewSecurityList creates a new security list with the given provider

func (*SecurityList) ApplyColumnSecurity

func (m *SecurityList) ApplyColumnSecurity(records reflect.Value, modelType reflect.Type, pUserID int, pSchema, pTablename string) (reflect.Value, error)

func (*SecurityList) ClearSecurity

func (m *SecurityList) ClearSecurity(pUserID int, pSchema, pTablename string) error

func (*SecurityList) ColumSecurityApplyOnRecord

func (m *SecurityList) ColumSecurityApplyOnRecord(prevRecord reflect.Value, newRecord reflect.Value, modelType reflect.Type, pUserID int, pSchema, pTablename string) ([]string, error)

func (*SecurityList) GetRowSecurityTemplate

func (m *SecurityList) GetRowSecurityTemplate(pUserID int, pSchema, pTablename string) (RowSecurity, error)

func (*SecurityList) LoadColumnSecurity

func (m *SecurityList) LoadColumnSecurity(ctx context.Context, pUserID int, pSchema, pTablename string, pOverwrite bool) error

func (*SecurityList) LoadRowSecurity

func (m *SecurityList) LoadRowSecurity(ctx context.Context, pUserID int, pSchema, pTablename string, pOverwrite bool) (RowSecurity, error)

func (*SecurityList) Provider added in v0.0.63

func (m *SecurityList) Provider() SecurityProvider

Provider returns the underlying security provider

type SecurityProvider added in v0.0.63

type SecurityProvider interface {
	Authenticator
	ColumnSecurityProvider
	RowSecurityProvider
}

SecurityProvider is the main interface combining all security concerns

type TOTPGenerator added in v1.0.48

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

TOTPGenerator handles TOTP code generation and validation

func NewTOTPGenerator added in v1.0.48

func NewTOTPGenerator(config *TwoFactorConfig) *TOTPGenerator

NewTOTPGenerator creates a new TOTP generator with config

func (*TOTPGenerator) GenerateCode added in v1.0.48

func (t *TOTPGenerator) GenerateCode(secret string, timestamp time.Time) (string, error)

GenerateCode creates a TOTP code for a given time

func (*TOTPGenerator) GenerateQRCodeURL added in v1.0.48

func (t *TOTPGenerator) GenerateQRCodeURL(secret, issuer, accountName string) string

GenerateQRCodeURL creates a URL for QR code generation

func (*TOTPGenerator) GenerateSecret added in v1.0.48

func (t *TOTPGenerator) GenerateSecret() (string, error)

GenerateSecret creates a random base32-encoded secret

func (*TOTPGenerator) ValidateCode added in v1.0.48

func (t *TOTPGenerator) ValidateCode(secret, code string) (bool, error)

ValidateCode checks if a code is valid for the secret

type TwoFactorAuthProvider added in v1.0.48

type TwoFactorAuthProvider interface {
	// Generate2FASecret creates a new secret for a user
	Generate2FASecret(userID int, issuer, accountName string) (*TwoFactorSecret, error)

	// Validate2FACode verifies a TOTP code
	Validate2FACode(secret string, code string) (bool, error)

	// Enable2FA activates 2FA for a user (store secret in your database)
	Enable2FA(userID int, secret string, backupCodes []string) error

	// Disable2FA deactivates 2FA for a user
	Disable2FA(userID int) error

	// Get2FAStatus checks if user has 2FA enabled
	Get2FAStatus(userID int) (bool, error)

	// Get2FASecret retrieves the user's 2FA secret
	Get2FASecret(userID int) (string, error)

	// GenerateBackupCodes creates backup codes for 2FA
	GenerateBackupCodes(userID int, count int) ([]string, error)

	// ValidateBackupCode checks and consumes a backup code
	ValidateBackupCode(userID int, code string) (bool, error)
}

TwoFactorAuthProvider defines interface for 2FA operations

type TwoFactorAuthenticator added in v1.0.48

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

TwoFactorAuthenticator wraps an Authenticator and adds 2FA support

func NewTwoFactorAuthenticator added in v1.0.48

func NewTwoFactorAuthenticator(baseAuth Authenticator, provider TwoFactorAuthProvider, config *TwoFactorConfig) *TwoFactorAuthenticator

NewTwoFactorAuthenticator creates a new 2FA-enabled authenticator

func (*TwoFactorAuthenticator) Authenticate added in v1.0.48

func (t *TwoFactorAuthenticator) Authenticate(r *http.Request) (*UserContext, error)

Authenticate delegates to base authenticator

func (*TwoFactorAuthenticator) Disable2FA added in v1.0.48

func (t *TwoFactorAuthenticator) Disable2FA(userID int) error

Disable2FA removes 2FA from a user account

func (*TwoFactorAuthenticator) Enable2FA added in v1.0.48

func (t *TwoFactorAuthenticator) Enable2FA(userID int, secret, verificationCode string) error

Enable2FA completes 2FA setup after user confirms with a valid code

func (*TwoFactorAuthenticator) Login added in v1.0.48

Login authenticates with 2FA support

func (*TwoFactorAuthenticator) Logout added in v1.0.48

Logout delegates to base authenticator

func (*TwoFactorAuthenticator) RegenerateBackupCodes added in v1.0.48

func (t *TwoFactorAuthenticator) RegenerateBackupCodes(userID int, count int) ([]string, error)

RegenerateBackupCodes creates new backup codes for a user

func (*TwoFactorAuthenticator) Setup2FA added in v1.0.48

func (t *TwoFactorAuthenticator) Setup2FA(userID int, issuer, accountName string) (*TwoFactorSecret, error)

Setup2FA initiates 2FA setup for a user

type TwoFactorConfig added in v1.0.48

type TwoFactorConfig struct {
	Algorithm  string // SHA1, SHA256, SHA512
	Digits     int    // Number of digits in code (6 or 8)
	Period     int    // Time step in seconds (default 30)
	SkewWindow int    // Number of time steps to check before/after (default 1)
}

TwoFactorConfig holds TOTP configuration

func DefaultTwoFactorConfig added in v1.0.48

func DefaultTwoFactorConfig() *TwoFactorConfig

DefaultTwoFactorConfig returns standard TOTP configuration

type TwoFactorSecret added in v1.0.48

type TwoFactorSecret struct {
	Secret      string   `json:"secret"`       // Base32 encoded secret
	QRCodeURL   string   `json:"qr_code_url"`  // URL for QR code generation
	BackupCodes []string `json:"backup_codes"` // One-time backup codes
	Issuer      string   `json:"issuer"`       // Application name
	AccountName string   `json:"account_name"` // User identifier (email/username)
}

TwoFactorSecret contains 2FA setup information

type UserContext added in v0.0.63

type UserContext struct {
	UserID           int            `json:"user_id"`
	UserName         string         `json:"user_name"`
	UserLevel        int            `json:"user_level"`
	SessionID        string         `json:"session_id"`
	SessionRID       int64          `json:"session_rid"`
	RemoteID         string         `json:"remote_id"`
	Roles            []string       `json:"roles"`
	Email            string         `json:"email"`
	Claims           map[string]any `json:"claims"`
	Meta             map[string]any `json:"meta"`               // Additional metadata that can hold any JSON-serializable values
	TwoFactorEnabled bool           `json:"two_factor_enabled"` // Indicates if 2FA is enabled for this user
}

UserContext holds authenticated user information

func GetUserContext added in v0.0.63

func GetUserContext(ctx context.Context) (*UserContext, bool)

GetUserContext extracts the full user context from request context

type Validatable added in v0.0.63

type Validatable interface {
	// ValidateToken checks if a token is valid without extracting full user context
	ValidateToken(ctx context.Context, token string) (bool, error)
}

Validatable allows providers to validate tokens without full authentication

Jump to

Keyboard shortcuts

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