stepup

package
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Jan 3, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

Step-Up Authentication Plugin

Enterprise-grade step-up authentication for AuthSome with context-aware verification requirements.

Overview

The step-up authentication plugin provides adaptive security for high-value operations by requiring additional verification based on:

  • 🛣️ Route patterns - Sensitive endpoints require re-authentication
  • 💰 Transaction amounts - Higher amounts need stronger verification
  • 📦 Resource sensitivity - Critical resources require step-up
  • Time-based rules - Re-auth after inactivity periods
  • 🎯 Risk scores - Adaptive security based on risk assessment
  • 🏢 Multi-tenancy - Organization-scoped policies and overrides

Key Features

Security Levels

Four graduated security levels with configurable verification methods:

  • Low - Basic authentication (logged in)
  • Medium - Re-authentication within 15 minutes (password)
  • High - Strong re-auth within 5 minutes (password + 2FA)
  • Critical - Immediate verification (password + biometric/WebAuthn)
Rule Types
  1. Route Rules - Pattern-based route protection
  2. Amount Rules - Transaction value thresholds
  3. Resource Rules - Sensitivity-based access control
  4. Time-Based Rules - Age-based re-authentication
  5. Context Rules - Custom condition evaluation
  6. Risk-Based Rules - Adaptive security levels
User Experience
  • ✅ Device remembering (24-hour default)
  • ✅ Grace periods (30 seconds)
  • ✅ Clear prompts and error messages
  • ✅ Multiple verification methods
  • ✅ Graceful degradation
Multi-Tenancy Support
  • Organization-scoped rules and policies
  • Per-org configuration overrides
  • Global and organization-specific rules
  • User-specific policy overrides

Installation

1. Register the Plugin
import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/stepup"
)

// Create AuthSome instance
auth := authsome.New(
    authsome.WithDatabase(db),
    authsome.WithForgeApp(app),
)

// Register step-up plugin
stepupPlugin := stepup.NewPlugin(nil) // Use default config
auth.RegisterPlugin(stepupPlugin)

// Initialize
if err := auth.Initialize(ctx); err != nil {
    log.Fatal(err)
}

// Mount routes
auth.Mount(router, "/api/auth")
2. Run Migrations

Migrations run automatically during plugin initialization, creating these tables:

  • stepup_verifications - Verification records
  • stepup_requirements - Pending requirements
  • stepup_remembered_devices - Trusted devices
  • stepup_attempts - Verification attempts
  • stepup_policies - Organization policies
  • stepup_audit_logs - Audit trail

Configuration

Basic Configuration
config := &stepup.Config{
    Enabled: true,
    
    // Time windows
    MediumAuthWindow:   15 * time.Minute,
    HighAuthWindow:     5 * time.Minute,
    CriticalAuthWindow: 0, // Immediate
    
    // Verification methods per level
    LowMethods:      []stepup.VerificationMethod{stepup.MethodPassword},
    MediumMethods:   []stepup.VerificationMethod{stepup.MethodPassword},
    HighMethods:     []stepup.VerificationMethod{stepup.MethodPassword, stepup.MethodTOTP},
    CriticalMethods: []stepup.VerificationMethod{stepup.MethodPassword, stepup.MethodWebAuthn},
    
    // Device remembering
    RememberStepUp:   true,
    RememberDuration: 24 * time.Hour,
    
    // Risk-based adaptive security
    RiskBasedEnabled: true,
}

plugin := stepup.NewPlugin(config)
Route Rules
config := stepup.DefaultConfig()
config.RouteRules = []stepup.RouteRule{
    {
        Pattern:       "/api/user/email",
        Method:        "PUT",
        SecurityLevel: stepup.SecurityLevelMedium,
        Description:   "Changing email requires re-authentication",
    },
    {
        Pattern:       "/api/user/password",
        Method:        "PUT",
        SecurityLevel: stepup.SecurityLevelHigh,
        Description:   "Changing password requires strong authentication",
    },
    {
        Pattern:       "/api/payment/*",
        Method:        "POST",
        SecurityLevel: stepup.SecurityLevelMedium,
        Description:   "Payment operations require verification",
    },
}
Amount Rules
config.AmountRules = []stepup.AmountRule{
    {
        MinAmount:     0,
        MaxAmount:     1000,
        Currency:      "USD",
        SecurityLevel: stepup.SecurityLevelMedium,
        Description:   "Amounts under $1,000 require medium security",
    },
    {
        MinAmount:     1000,
        MaxAmount:     10000,
        Currency:      "USD",
        SecurityLevel: stepup.SecurityLevelHigh,
        Description:   "Amounts $1,000-$10,000 require high security",
    },
    {
        MinAmount:     10000,
        MaxAmount:     0, // Unlimited
        Currency:      "USD",
        SecurityLevel: stepup.SecurityLevelCritical,
        Description:   "Amounts over $10,000 require critical security",
    },
}
Resource Rules
config.ResourceRules = []stepup.ResourceRule{
    {
        ResourceType:  "user",
        Action:        "delete",
        SecurityLevel: stepup.SecurityLevelHigh,
        Sensitivity:   "high",
        Description:   "Deleting user account requires high security",
    },
    {
        ResourceType:  "settings",
        Action:        "update",
        SecurityLevel: stepup.SecurityLevelMedium,
        Sensitivity:   "medium",
        Description:   "Updating security settings requires verification",
    },
}
Organization-Specific Rules

Rules can be scoped to specific organizations:

config.RouteRules = []stepup.RouteRule{
    {
        Pattern:       "/api/admin/*",
        Method:        "POST",
        SecurityLevel: stepup.SecurityLevelHigh,
        OrgID:         "org_enterprise_123", // Only for this org
        Description:   "Enterprise org requires high security for admin operations",
    },
}

Usage Examples

1. Route-Based Protection

Automatically enforce step-up for specific routes:

// Apply to all routes (checks configured rules)
router.Use(stepupPlugin.Middleware().RequireForRoute())

// Or apply to specific route groups
adminRoutes := router.Group("/api/admin")
adminRoutes.Use(stepupPlugin.Middleware().RequireLevel(stepup.SecurityLevelHigh))
adminRoutes.POST("/users/delete", deleteUserHandler)
2. Amount-Based Protection

For financial transactions:

func transferHandler(c forge.Context) error {
    var req TransferRequest
    c.BindJSON(&req)
    
    // Apply amount-based middleware
    middleware := stepupPlugin.Middleware().RequireForAmount(req.Amount, req.Currency)
    
    // Check if step-up is required
    if err := middleware(func(c forge.Context) error {
        // Process transfer
        return processTransfer(c, req)
    })(c); err != nil {
        return err
    }
    
    return nil
}
3. Resource-Based Protection

For sensitive resource operations:

func deleteAccountHandler(c forge.Context) error {
    // Require high security for account deletion
    middleware := stepupPlugin.Middleware().RequireForResource("user", "delete")
    
    return middleware(func(c forge.Context) error {
        // Delete account
        return deleteAccount(c)
    })(c)
}
4. Manual Evaluation

For custom logic:

func sensitiveOperation(c forge.Context) error {
    service := stepupPlugin.Service()
    
    evalCtx := &stepup.EvaluationContext{
        UserID:    getUserID(c),
        OrgID:     getOrgID(c),
        Route:     c.Request().URL.Path,
        Method:    c.Request().Method,
        Amount:    15000.00,
        Currency:  "USD",
        IP:        c.Request().RemoteAddr,
        UserAgent: c.Request().Header.Get("User-Agent"),
        DeviceID:  getDeviceID(c),
    }
    
    result, err := service.EvaluateRequirement(c.Request().Context(), evalCtx)
    if err != nil {
        return c.JSON(500, map[string]interface{}{"error": "Evaluation failed"})
    }
    
    if result.Required {
        return c.JSON(403, map[string]interface{}{
            "error":           "Step-up required",
            "requirement_id":  result.RequirementID,
            "challenge_token": result.ChallengeToken,
            "allowed_methods": result.AllowedMethods,
        })
    }
    
    // Continue with operation
    return performOperation(c)
}
5. Verification Flow

Client-side verification process:

// 1. Attempt operation
const response = await fetch('/api/user/email', {
  method: 'PUT',
  body: JSON.stringify({ email: 'new@example.com' })
});

// 2. Check if step-up is required
if (response.status === 403) {
  const data = await response.json();
  
  if (data.error === 'Step-up authentication required') {
    // Show step-up dialog
    showStepUpDialog({
      level: data.security_level,
      reason: data.reason,
      methods: data.allowed_methods,
      challengeToken: data.challenge_token
    });
  }
}

// 3. User enters verification (e.g., password)
async function verifyStepUp(password, challengeToken, rememberDevice) {
  const response = await fetch('/api/auth/stepup/verify', {
    method: 'POST',
    body: JSON.stringify({
      challenge_token: challengeToken,
      method: 'password',
      credential: password,
      remember_device: rememberDevice,
      device_id: getDeviceID()
    })
  });
  
  if (response.ok) {
    // Step-up successful, retry original operation
    retryOriginalOperation();
  }
}

API Endpoints

Evaluation

POST /stepup/evaluate

Evaluate if step-up is required for an operation:

curl -X POST /api/auth/stepup/evaluate \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "route": "/api/payment/transfer",
    "method": "POST",
    "amount": 5000,
    "currency": "USD"
  }'

Response:

{
  "required": true,
  "security_level": "high",
  "current_level": "medium",
  "matched_rules": ["Amount: 5000.00 USD"],
  "reason": "Amounts $1,000-$10,000 require high security",
  "requirement_id": "req_abc123",
  "challenge_token": "token_xyz789",
  "allowed_methods": ["password", "totp"],
  "expires_at": "2025-11-01T12:30:00Z",
  "can_remember": true
}
Verification

POST /stepup/verify

Verify step-up authentication:

curl -X POST /api/auth/stepup/verify \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "challenge_token": "token_xyz789",
    "method": "password",
    "credential": "user_password",
    "remember_device": true,
    "device_id": "device_123"
  }'

Response:

{
  "success": true,
  "verification_id": "ver_def456",
  "security_level": "high",
  "expires_at": "2025-11-01T12:35:00Z",
  "device_remembered": true
}
Status

GET /stepup/status

Get current step-up status:

curl /api/auth/stepup/status \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "enabled": true,
  "current_level": "medium",
  "pending_count": 0,
  "remembered_devices": 2,
  "remember_enabled": true,
  "risk_based_enabled": true
}
Requirements

GET /stepup/requirements/pending

List pending step-up requirements:

curl /api/auth/stepup/requirements/pending \
  -H "Authorization: Bearer $TOKEN"

GET /stepup/requirements/:id

Get specific requirement details.

Verifications

GET /stepup/verifications

List verification history with pagination:

curl "/api/auth/stepup/verifications?limit=20&offset=0" \
  -H "Authorization: Bearer $TOKEN"
Remembered Devices

GET /stepup/devices

List remembered devices:

curl /api/auth/stepup/devices \
  -H "Authorization: Bearer $TOKEN"

DELETE /stepup/devices/:id

Forget a remembered device:

curl -X DELETE /api/auth/stepup/devices/device_123 \
  -H "Authorization: Bearer $TOKEN"
Policies

POST /stepup/policies

Create organization-specific policy:

curl -X POST /api/auth/stepup/policies \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "name": "High-Value Transactions",
    "description": "Require critical security for transactions over $50k",
    "enabled": true,
    "priority": 100,
    "rules": {
      "amount_threshold": 50000,
      "security_level": "critical"
    }
  }'

GET /stepup/policies

List organization policies.

PUT /stepup/policies/:id

Update policy.

DELETE /stepup/policies/:id

Delete policy.

Audit Logs

GET /stepup/audit

Get audit logs with pagination:

curl "/api/auth/stepup/audit?limit=50&offset=0" \
  -H "Authorization: Bearer $TOKEN"

Real-World Examples

Example 1: Email Change
// Changing email requires re-authentication
router.PUT("/api/user/email", func(c forge.Context) error {
    // Step-up middleware checks automatically
    var req struct {
        NewEmail string `json:"new_email"`
    }
    c.BindJSON(&req)
    
    // If we get here, step-up was satisfied
    return updateEmail(c, req.NewEmail)
}, stepupPlugin.Middleware().RequireLevel(stepup.SecurityLevelMedium))
Example 2: Large Transfer
// Transfer $10k requires biometric
func transferMoney(c forge.Context) error {
    var req TransferRequest
    c.BindJSON(&req)
    
    service := stepupPlugin.Service()
    result, _ := service.EvaluateRequirement(c.Request().Context(), &stepup.EvaluationContext{
        UserID:   getUserID(c),
        OrgID:    getOrgID(c),
        Amount:   req.Amount,
        Currency: req.Currency,
    })
    
    if result.Required {
        return c.JSON(403, map[string]interface{}{
            "error":          "Additional verification required",
            "required_level": result.SecurityLevel,
            "reason":         fmt.Sprintf("Transferring %.2f %s requires %s security", 
                req.Amount, req.Currency, result.SecurityLevel),
            "challenge_token": result.ChallengeToken,
            "allowed_methods": result.AllowedMethods,
        })
    }
    
    return processTransfer(c, req)
}
Example 3: Account Deletion
// Deleting account requires password + 2FA
router.DELETE("/api/user/account", 
    stepupPlugin.Middleware().RequireForResource("user", "delete"),
    func(c forge.Context) error {
        // Delete account
        return deleteUserAccount(c)
    },
)

Advanced Features

Risk-Based Adaptive Security

Enable risk-based evaluation:

config := stepup.DefaultConfig()
config.RiskBasedEnabled = true
config.RiskThresholdLow = 0.3    // Risk score > 0.3 = medium security
config.RiskThresholdMedium = 0.6 // Risk score > 0.6 = high security
config.RiskThresholdHigh = 0.8   // Risk score > 0.8 = critical security

Then provide risk scores in evaluation:

evalCtx := &stepup.EvaluationContext{
    UserID:    userID,
    OrgID:     orgID,
    RiskScore: 0.75, // High risk - will require high security
    // ... other fields
}
Device Remembering

Users can remember their device for 24 hours:

// During verification, user checks "Remember this device"
await fetch('/api/auth/stepup/verify', {
  method: 'POST',
  body: JSON.stringify({
    challenge_token: token,
    method: 'password',
    credential: password,
    remember_device: true,
    device_id: generateDeviceID(), // Persistent device identifier
    device_name: 'Chrome on MacBook Pro'
  })
});
Cleanup Scheduler

Start automatic cleanup of expired records:

// Start cleanup every hour
stepupPlugin.StartCleanupScheduler(1 * time.Hour)
Organization Overrides

Organizations can override global rules:

// Create org-specific policy via API
POST /api/auth/stepup/policies
{
  "name": "Enterprise Security Policy",
  "description": "Stricter rules for enterprise org",
  "enabled": true,
  "priority": 200, // Higher priority than global rules
  "rules": {
    "route_rules": [{
      "pattern": "/api/*",
      "security_level": "high"
    }]
  }
}

Security Considerations

Best Practices
  1. Start Conservative - Begin with stricter rules, relax as needed
  2. Monitor Patterns - Review audit logs for false positives
  3. User Education - Clearly communicate why step-up is required
  4. Graceful Degradation - Allow degraded experience if verification unavailable
  5. Device Fingerprinting - Use robust device identification
  6. Rate Limiting - Limit verification attempts
  7. Audit Everything - Log all step-up events
Integration with MFA

Step-up works alongside MFA plugin:

// Register both plugins
auth.RegisterPlugin(mfaPlugin)
auth.RegisterPlugin(stepupPlugin)

// Configure step-up to require MFA for high security
config := stepup.DefaultConfig()
config.HighMethods = []stepup.VerificationMethod{
    stepup.MethodPassword,
    stepup.MethodTOTP, // Requires MFA plugin
}

Performance

Caching

Current security levels are cached to avoid repeated database queries:

  • Verifications are cached until expiry
  • Remembered devices checked first
  • Redis recommended for distributed systems
Indexes

All tables have optimized indexes for:

  • User/org lookups
  • Status queries
  • Time-based queries
  • Token lookups
Cleanup

Automatic cleanup prevents table bloat:

  • Expired requirements (default: 10 minutes)
  • Expired verifications (default: per security level)
  • Expired remembered devices (default: 24 hours)

Monitoring

Audit Events

All step-up events are logged:

  • stepup.required - Step-up was required
  • stepup.initiated - User initiated verification
  • stepup.verified - Verification succeeded
  • stepup.failed - Verification failed
  • stepup.bypassed - Step-up bypassed (remembered device)
  • stepup.device_forgotten - User forgot device
Metrics to Track

Recommended metrics:

  • Step-up requirement rate
  • Verification success rate
  • Average time to verify
  • Remembered device usage
  • Failed attempt rate
  • Rule match distribution

Troubleshooting

Step-Up Always Required

Check current authentication level:

curl /api/auth/stepup/status

Possible causes:

  • User session expired
  • Verification expired
  • Too strict rules
Verification Failing

Check:

  1. Requirement not expired
  2. Correct verification method
  3. Valid credentials
  4. Not rate limited
Device Not Remembered

Verify:

  • remember_device set to true
  • Consistent device_id across requests
  • Device cookie not cleared
  • Device not expired (24h default)

License

This plugin is part of the AuthSome framework and follows the same license.

Support

For issues and questions:

Documentation

Overview

Package stepup provides context-aware step-up authentication for AuthSome.

The step-up authentication plugin adds adaptive security to AuthSome by requiring additional verification for high-value or sensitive operations. Unlike always-on 2FA, step-up authentication is context-aware and only triggers when needed based on configurable rules.

Key Features

  • Context-aware verification (route, amount, resource-based)
  • Four graduated security levels (Low, Medium, High, Critical)
  • Multiple verification methods (Password, TOTP, SMS, Email, Biometric, WebAuthn)
  • Device remembering for trusted devices
  • Risk-based adaptive security
  • Multi-tenant organization-scoped policies
  • Time-based re-authentication requirements
  • Comprehensive audit trail

Quick Start

Basic setup with default configuration:

auth := authsome.New(
    authsome.WithDatabase(db),
    authsome.WithForgeApp(app),
)

stepupPlugin := stepup.NewPlugin(nil) // Use default config
auth.RegisterPlugin(stepupPlugin)
auth.Initialize(ctx)
auth.Mount(app.Router(), "/api/auth")

Route Protection

Protect routes with middleware:

// Automatic route-based protection
router.Use(stepupPlugin.Middleware().RequireForRoute())

// Specific security level requirement
adminRoutes := router.Group("/api/admin")
adminRoutes.Use(stepupPlugin.Middleware().RequireLevel(stepup.SecurityLevelHigh))
adminRoutes.POST("/users/delete", deleteUserHandler)

Manual Evaluation

For custom logic, manually evaluate step-up requirements:

service := stepupPlugin.Service()
result, err := service.EvaluateRequirement(ctx, &stepup.EvaluationContext{
    UserID:    userID,
    OrgID:     orgID,
    Route:     "/api/transfer",
    Method:    "POST",
    Amount:    5000,
    Currency:  "USD",
})

if result.Required {
    return c.JSON(403, map[string]interface{}{
        "error":           "step_up_required",
        "challenge_token": result.ChallengeToken,
        "allowed_methods": result.AllowedMethods,
    })
}

Configuration

Customize configuration for your needs:

config := &stepup.Config{
    Enabled: true,

    // Time windows for re-authentication
    MediumAuthWindow:   15 * time.Minute,
    HighAuthWindow:     5 * time.Minute,
    CriticalAuthWindow: 0, // Immediate

    // Route-based rules
    RouteRules: []stepup.RouteRule{
        {
            Pattern:       "/api/user/email",
            Method:        "PUT",
            SecurityLevel: stepup.SecurityLevelMedium,
            Description:   "Email changes require password",
        },
        {
            Pattern:       "/api/user/password",
            Method:        "PUT",
            SecurityLevel: stepup.SecurityLevelHigh,
            Description:   "Password changes require 2FA",
        },
    },

    // Amount-based rules
    AmountRules: []stepup.AmountRule{
        {
            MinAmount:     10000,
            MaxAmount:     0,
            Currency:      "USD",
            SecurityLevel: stepup.SecurityLevelCritical,
            Description:   "Large transfers require biometric",
        },
    },

    // Device remembering
    RememberStepUp:   true,
    RememberDuration: 24 * time.Hour,

    // Risk-based security
    RiskBasedEnabled: true,
}

plugin := stepup.NewPlugin(config)

Security Levels

Four graduated security levels with different requirements:

  • Low: Basic authentication (user is logged in)
  • Medium: Re-authentication within time window (e.g., password)
  • High: Strong authentication (e.g., password + TOTP)
  • Critical: Immediate strong authentication (e.g., password + biometric)

Each level can require different verification methods:

config.HighMethods = []stepup.VerificationMethod{
    stepup.MethodPassword,
    stepup.MethodTOTP,
}

Rule Types

Five types of rules for different scenarios:

1. Route Rules - Pattern-based route protection:

RouteRule{
    Pattern:       "/api/admin/*",
    Method:        "*",
    SecurityLevel: SecurityLevelHigh,
}

2. Amount Rules - Transaction value thresholds:

AmountRule{
    MinAmount:     1000,
    MaxAmount:     10000,
    Currency:      "USD",
    SecurityLevel: SecurityLevelHigh,
}

3. Resource Rules - Sensitivity-based access:

ResourceRule{
    ResourceType:  "user",
    Action:        "delete",
    SecurityLevel: SecurityLevelHigh,
}

4. Time-Based Rules - Authentication age limits:

TimeBasedRule{
    Operation:     "admin_action",
    MaxAge:        5 * time.Minute,
    SecurityLevel: SecurityLevelHigh,
}

5. Context Rules - Custom condition evaluation:

ContextRule{
    Name:          "suspicious_activity",
    Condition:     "risk_score > 0.8",
    SecurityLevel: SecurityLevelCritical,
}

Multi-Tenancy

Full support for organization-scoped rules and policies:

// Global rule (applies to all organizations)
RouteRule{
    Pattern:       "/api/admin/*",
    SecurityLevel: SecurityLevelMedium,
    OrgID:         "", // Empty = global
}

// Organization-specific rule
RouteRule{
    Pattern:       "/api/admin/*",
    SecurityLevel: SecurityLevelHigh,
    OrgID:         "org_enterprise_123",
}

Organizations can create custom policies:

policy := &stepup.StepUpPolicy{
    OrgID:       "org_123",
    Name:        "Enterprise Security Policy",
    Priority:    100, // Higher priority = evaluated first
    Enabled:     true,
    Rules:       {...},
}

Device Remembering

Users can remember trusted devices for 24 hours (configurable):

verifyReq := &stepup.VerifyRequest{
    ChallengeToken: challengeToken,
    Method:         stepup.MethodPassword,
    Credential:     password,
    RememberDevice: true,
    DeviceID:       "device_xyz",
    DeviceName:     "Chrome on MacBook Pro",
}

response, err := service.VerifyStepUp(ctx, verifyReq)

Risk-Based Adaptive Security

Automatically adjust security requirements based on risk scores:

config := stepup.DefaultConfig()
config.RiskBasedEnabled = true
config.RiskThresholdLow = 0.3
config.RiskThresholdMedium = 0.6
config.RiskThresholdHigh = 0.8

evalCtx := &stepup.EvaluationContext{
    UserID:    userID,
    RiskScore: 0.75, // High risk - will require high security
}

Client-Side Integration

Example JavaScript client for handling step-up flow:

async function transferMoney(amount) {
    const response = await fetch('/api/transfer', {
        method: 'POST',
        body: JSON.stringify({ amount })
    });

    if (response.status === 403) {
        const data = await response.json();

        if (data.error === 'step_up_required') {
            // Show step-up dialog
            const credential = await showStepUpDialog(data);

            // Verify step-up
            await fetch('/api/auth/stepup/verify', {
                method: 'POST',
                body: JSON.stringify({
                    challenge_token: data.challenge_token,
                    method: 'password',
                    credential: credential,
                    remember_device: true
                })
            });

            // Retry original request
            return transferMoney(amount);
        }
    }

    return response.json();
}

API Endpoints

The plugin registers the following endpoints:

  • POST /stepup/evaluate - Evaluate if step-up is required
  • POST /stepup/verify - Verify step-up authentication
  • GET /stepup/status - Get current step-up status
  • GET /stepup/requirements/:id - Get requirement details
  • GET /stepup/requirements/pending - List pending requirements
  • GET /stepup/verifications - List verification history
  • GET /stepup/devices - List remembered devices
  • DELETE /stepup/devices/:id - Forget device
  • POST /stepup/policies - Create organization policy
  • GET /stepup/policies - List policies
  • GET /stepup/policies/:id - Get policy
  • PUT /stepup/policies/:id - Update policy
  • DELETE /stepup/policies/:id - Delete policy
  • GET /stepup/audit - Get audit logs

Audit and Monitoring

All step-up events are audited:

  • stepup.required - Step-up was required
  • stepup.initiated - User initiated verification
  • stepup.verified - Verification succeeded
  • stepup.failed - Verification failed
  • stepup.bypassed - Step-up bypassed (remembered device)
  • stepup.device_forgotten - User forgot device

Enable audit logging in configuration:

config := stepup.DefaultConfig()
config.AuditEnabled = true
config.AuditEvents = []string{
    "stepup.required",
    "stepup.verified",
    "stepup.failed",
}

Cleanup Scheduler

Start automatic cleanup of expired records:

stepupPlugin.StartCleanupScheduler(1 * time.Hour)

This removes:

  • Expired requirements (10 minute TTL)
  • Expired verifications (per security level TTL)
  • Expired remembered devices (24 hour default)

Performance Considerations

The plugin is optimized for production use:

  • Database indexes on all query patterns
  • Minimal database queries (cached verifications)
  • Efficient rule evaluation (O(n) where n = number of rules)
  • Background cleanup (doesn't block requests)
  • Stateless design (works with load balancers)

Testing

The plugin includes comprehensive tests. Example:

func TestStepUpFlow(t *testing.T) {
    // Setup
    repo := new(mockRepository)
    service := stepup.NewService(repo, stepup.DefaultConfig(), nil)

    // Test evaluation
    result, err := service.EvaluateRequirement(ctx, &stepup.EvaluationContext{
        UserID:   "user123",
        Amount:   5000,
        Currency: "USD",
    })

    assert.NoError(t, err)
    assert.True(t, result.Required)
    assert.Equal(t, stepup.SecurityLevelHigh, result.SecurityLevel)
}

Error Handling

All errors are wrapped with context:

result, err := service.EvaluateRequirement(ctx, evalCtx)
if err != nil {
    return fmt.Errorf("failed to evaluate step-up: %w", err)
}

Error responses include helpful information:

{
    "error": "step_up_required",
    "security_level": "high",
    "reason": "Transferring $5,000.00 USD requires high security",
    "challenge_token": "token_xyz",
    "allowed_methods": ["password", "totp"]
}

Best Practices

  1. Start Conservative - Begin with stricter rules, relax as needed
  2. Monitor Patterns - Review audit logs for optimization opportunities
  3. User Communication - Clearly explain why verification is required
  4. Graceful Degradation - Handle failures gracefully
  5. Test Thoroughly - Test all security levels and edge cases
  6. Regular Review - Review and update rules periodically
  7. Performance - Use caching for high-traffic routes

Documentation

See the following files for more information:

  • README.md - Comprehensive guide with API documentation
  • EXAMPLE.md - Practical examples with client code
  • INTEGRATION.md - Integration guide for different patterns
  • SUMMARY.md - Implementation summary and architecture

Support

Index

Constants

View Source
const (
	PluginID      = "stepup"
	PluginName    = "Step-Up Authentication"
	PluginVersion = "1.0.0"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AmountRule

type AmountRule struct {
	MinAmount     float64       `json:"min_amount" yaml:"min_amount"`         // Minimum amount threshold
	MaxAmount     float64       `json:"max_amount" yaml:"max_amount"`         // Maximum amount threshold (0 for unlimited)
	Currency      string        `json:"currency" yaml:"currency"`             // Currency code (USD, EUR, etc.)
	SecurityLevel SecurityLevel `json:"security_level" yaml:"security_level"` // Required security level
	Description   string        `json:"description" yaml:"description"`       // Human-readable description
	OrgID         string        `json:"org_id" yaml:"org_id"`                 // Organization-specific
}

AmountRule defines step-up requirements based on monetary amounts

type AuditServiceInterface

type AuditServiceInterface interface {
	Log(ctx context.Context, event *audit.Event) error
}

AuditServiceInterface defines the interface for audit logging

type BunRepository

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

BunRepository implements Repository using Bun ORM

func NewBunRepository

func NewBunRepository(db *bun.DB) *BunRepository

NewBunRepository creates a new Bun-based repository

func (*BunRepository) CountFailedAttempts

func (r *BunRepository) CountFailedAttempts(ctx context.Context, userID, orgID string, since time.Time) (int, error)

func (*BunRepository) CreateAttempt

func (r *BunRepository) CreateAttempt(ctx context.Context, attempt *StepUpAttempt) error

func (*BunRepository) CreateAuditLog

func (r *BunRepository) CreateAuditLog(ctx context.Context, log *StepUpAuditLog) error

func (*BunRepository) CreatePolicy

func (r *BunRepository) CreatePolicy(ctx context.Context, policy *StepUpPolicy) error

func (*BunRepository) CreateRememberedDevice

func (r *BunRepository) CreateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error

func (*BunRepository) CreateRequirement

func (r *BunRepository) CreateRequirement(ctx context.Context, requirement *StepUpRequirement) error

func (*BunRepository) CreateVerification

func (r *BunRepository) CreateVerification(ctx context.Context, verification *StepUpVerification) error

func (*BunRepository) DeleteExpiredRememberedDevices

func (r *BunRepository) DeleteExpiredRememberedDevices(ctx context.Context) error

func (*BunRepository) DeleteExpiredRequirements

func (r *BunRepository) DeleteExpiredRequirements(ctx context.Context) error

func (*BunRepository) DeletePolicy

func (r *BunRepository) DeletePolicy(ctx context.Context, id string) error

func (*BunRepository) DeleteRememberedDevice

func (r *BunRepository) DeleteRememberedDevice(ctx context.Context, id string) error

func (*BunRepository) GetLatestVerification

func (r *BunRepository) GetLatestVerification(ctx context.Context, userID, orgID string, level SecurityLevel) (*StepUpVerification, error)

func (*BunRepository) GetPolicy

func (r *BunRepository) GetPolicy(ctx context.Context, id string) (*StepUpPolicy, error)

func (*BunRepository) GetRememberedDevice

func (r *BunRepository) GetRememberedDevice(ctx context.Context, userID, orgID, deviceID string) (*StepUpRememberedDevice, error)

func (*BunRepository) GetRequirement

func (r *BunRepository) GetRequirement(ctx context.Context, id string) (*StepUpRequirement, error)

func (*BunRepository) GetRequirementByToken

func (r *BunRepository) GetRequirementByToken(ctx context.Context, token string) (*StepUpRequirement, error)

func (*BunRepository) GetVerification

func (r *BunRepository) GetVerification(ctx context.Context, id string) (*StepUpVerification, error)

func (*BunRepository) ListAttempts

func (r *BunRepository) ListAttempts(ctx context.Context, requirementID string) ([]*StepUpAttempt, error)

func (*BunRepository) ListAuditLogs

func (r *BunRepository) ListAuditLogs(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpAuditLog, error)

func (*BunRepository) ListPendingRequirements

func (r *BunRepository) ListPendingRequirements(ctx context.Context, userID, orgID string) ([]*StepUpRequirement, error)

func (*BunRepository) ListPolicies

func (r *BunRepository) ListPolicies(ctx context.Context, orgID string) ([]*StepUpPolicy, error)

func (*BunRepository) ListRememberedDevices

func (r *BunRepository) ListRememberedDevices(ctx context.Context, userID, orgID string) ([]*StepUpRememberedDevice, error)

func (*BunRepository) ListVerifications

func (r *BunRepository) ListVerifications(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpVerification, error)

func (*BunRepository) UpdatePolicy

func (r *BunRepository) UpdatePolicy(ctx context.Context, policy *StepUpPolicy) error

func (*BunRepository) UpdateRememberedDevice

func (r *BunRepository) UpdateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error

func (*BunRepository) UpdateRequirement

func (r *BunRepository) UpdateRequirement(ctx context.Context, requirement *StepUpRequirement) error

type Config

type Config struct {
	// Global settings
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Time windows for different security levels
	MediumAuthWindow   time.Duration `json:"medium_auth_window" yaml:"medium_auth_window"`     // e.g., 15 minutes
	HighAuthWindow     time.Duration `json:"high_auth_window" yaml:"high_auth_window"`         // e.g., 5 minutes
	CriticalAuthWindow time.Duration `json:"critical_auth_window" yaml:"critical_auth_window"` // e.g., immediate

	// Verification method requirements per security level
	LowMethods      []VerificationMethod `json:"low_methods" yaml:"low_methods"`
	MediumMethods   []VerificationMethod `json:"medium_methods" yaml:"medium_methods"`
	HighMethods     []VerificationMethod `json:"high_methods" yaml:"high_methods"`
	CriticalMethods []VerificationMethod `json:"critical_methods" yaml:"critical_methods"`

	// Rule configuration
	RouteRules     []RouteRule     `json:"route_rules" yaml:"route_rules"`
	AmountRules    []AmountRule    `json:"amount_rules" yaml:"amount_rules"`
	ResourceRules  []ResourceRule  `json:"resource_rules" yaml:"resource_rules"`
	TimeBasedRules []TimeBasedRule `json:"time_based_rules" yaml:"time_based_rules"`
	ContextRules   []ContextRule   `json:"context_rules" yaml:"context_rules"`

	// Grace periods and remembering
	RememberStepUp   bool          `json:"remember_step_up" yaml:"remember_step_up"`   // Remember step-up per device
	RememberDuration time.Duration `json:"remember_duration" yaml:"remember_duration"` // How long to remember
	GracePeriod      time.Duration `json:"grace_period" yaml:"grace_period"`           // Grace period after step-up

	// User experience
	AllowDegradation bool   `json:"allow_degradation" yaml:"allow_degradation"` // Allow graceful degradation
	PromptMessage    string `json:"prompt_message" yaml:"prompt_message"`       // Custom prompt message
	RedirectURL      string `json:"redirect_url" yaml:"redirect_url"`           // Where to redirect for step-up

	// Risk-based adaptive requirements
	RiskBasedEnabled    bool    `json:"risk_based_enabled" yaml:"risk_based_enabled"`       // Enable adaptive security
	RiskThresholdLow    float64 `json:"risk_threshold_low" yaml:"risk_threshold_low"`       // Risk score for low security
	RiskThresholdMedium float64 `json:"risk_threshold_medium" yaml:"risk_threshold_medium"` // Risk score for medium security
	RiskThresholdHigh   float64 `json:"risk_threshold_high" yaml:"risk_threshold_high"`     // Risk score for high security

	// Organization-scoped overrides
	EnableOrgOverrides bool `json:"enable_org_overrides" yaml:"enable_org_overrides"`

	// Audit and monitoring
	AuditEnabled bool     `json:"audit_enabled" yaml:"audit_enabled"`
	AuditEvents  []string `json:"audit_events" yaml:"audit_events"` // Events to audit

	// Webhook notifications
	WebhookEnabled bool     `json:"webhook_enabled" yaml:"webhook_enabled"`
	WebhookEvents  []string `json:"webhook_events" yaml:"webhook_events"` // Events to webhook
}

Config holds the step-up authentication plugin configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default configuration

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

type ContextRule

type ContextRule struct {
	Name          string        `json:"name" yaml:"name"`                     // Rule name
	Condition     string        `json:"condition" yaml:"condition"`           // Condition expression (CEL or simple)
	SecurityLevel SecurityLevel `json:"security_level" yaml:"security_level"` // Required security level
	Description   string        `json:"description" yaml:"description"`       // Human-readable description
	OrgID         string        `json:"org_id" yaml:"org_id"`                 // Organization-specific
}

ContextRule defines step-up requirements based on contextual factors

type ErrorResponse

type ErrorResponse = responses.ErrorResponse

Response types - use shared responses from core

type EvaluateRequest

type EvaluateRequest struct {
	Route        string                 `json:"route,omitempty"`
	Method       string                 `json:"method,omitempty"`
	Amount       float64                `json:"amount,omitempty"`
	Currency     string                 `json:"currency,omitempty"`
	ResourceType string                 `json:"resource_type,omitempty"`
	Action       string                 `json:"action,omitempty"`
	Metadata     map[string]interface{} `json:"metadata,omitempty"`
}

EvaluateRequest is the request for evaluating step-up requirements

type EvaluationContext

type EvaluationContext struct {
	UserID       string
	OrgID        string
	SessionID    string
	Route        string
	Method       string
	Amount       float64
	Currency     string
	ResourceType string
	Action       string
	IP           string
	UserAgent    string
	DeviceID     string
	RiskScore    float64
	Metadata     map[string]interface{}
}

EvaluationContext contains context for evaluating step-up requirements

type EvaluationResult

type EvaluationResult struct {
	Required          bool                   `json:"required"`
	SecurityLevel     SecurityLevel          `json:"security_level,omitempty"`
	CurrentLevel      SecurityLevel          `json:"current_level"`
	MatchedRules      []string               `json:"matched_rules,omitempty"`
	Reason            string                 `json:"reason,omitempty"`
	RequirementID     string                 `json:"requirement_id,omitempty"`
	ChallengeToken    string                 `json:"challenge_token,omitempty"`
	AllowedMethods    []VerificationMethod   `json:"allowed_methods,omitempty"`
	ExpiresAt         time.Time              `json:"expires_at,omitempty"`
	GracePeriodEndsAt time.Time              `json:"grace_period_ends_at,omitempty"`
	CanRemember       bool                   `json:"can_remember"`
	Metadata          map[string]interface{} `json:"metadata,omitempty"`
}

EvaluationResult contains the result of step-up evaluation

func GetEvaluationFromContext

func GetEvaluationFromContext(c forge.Context) (*EvaluationResult, error)

GetEvaluationFromContext extracts the step-up evaluation result from context

type ForgetDeviceResponse

type ForgetDeviceResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

type Handler

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

Handler handles step-up HTTP requests

func NewHandler

func NewHandler(service *Service, config *Config) *Handler

NewHandler creates a new step-up handler

func (*Handler) CreatePolicy

func (h *Handler) CreatePolicy(c forge.Context) error

CreatePolicy handles POST /stepup/policies

func (*Handler) DeletePolicy

func (h *Handler) DeletePolicy(c forge.Context) error

DeletePolicy handles DELETE /stepup/policies/:id

func (*Handler) Evaluate

func (h *Handler) Evaluate(c forge.Context) error

Evaluate handles POST /stepup/evaluate

func (*Handler) ForgetDevice

func (h *Handler) ForgetDevice(c forge.Context) error

ForgetDevice handles DELETE /stepup/devices/:id

func (*Handler) GetAuditLogs

func (h *Handler) GetAuditLogs(c forge.Context) error

GetAuditLogs handles GET /stepup/audit

func (*Handler) GetPolicy

func (h *Handler) GetPolicy(c forge.Context) error

GetPolicy handles GET /stepup/policies/:id

func (*Handler) GetRequirement

func (h *Handler) GetRequirement(c forge.Context) error

GetRequirement handles GET /stepup/requirements/:id

func (*Handler) ListPendingRequirements

func (h *Handler) ListPendingRequirements(c forge.Context) error

ListPendingRequirements handles GET /stepup/requirements/pending

func (*Handler) ListPolicies

func (h *Handler) ListPolicies(c forge.Context) error

ListPolicies handles GET /stepup/policies

func (*Handler) ListRememberedDevices

func (h *Handler) ListRememberedDevices(c forge.Context) error

ListRememberedDevices handles GET /stepup/devices

func (*Handler) ListVerifications

func (h *Handler) ListVerifications(c forge.Context) error

ListVerifications handles GET /stepup/verifications

func (*Handler) Status

func (h *Handler) Status(c forge.Context) error

Status handles GET /stepup/status

func (*Handler) UpdatePolicy

func (h *Handler) UpdatePolicy(c forge.Context) error

UpdatePolicy handles PUT /stepup/policies/:id

func (*Handler) Verify

func (h *Handler) Verify(c forge.Context) error

Verify handles POST /stepup/verify

type MessageResponse

type MessageResponse = responses.MessageResponse

type Middleware

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

Middleware provides step-up authentication middleware

func NewMiddleware

func NewMiddleware(service *Service, config *Config) *Middleware

NewMiddleware creates a new step-up middleware

func (*Middleware) EvaluateMiddleware

func (m *Middleware) EvaluateMiddleware() forge.Middleware

EvaluateMiddleware evaluates but doesn't block - stores result in context

func (*Middleware) RequireForAmount

func (m *Middleware) RequireForAmount(amount float64, currency string) forge.Middleware

RequireForAmount returns middleware that checks amount-based rules

func (*Middleware) RequireForResource

func (m *Middleware) RequireForResource(resourceType, action string) forge.Middleware

RequireForResource returns middleware that checks resource-based rules

func (*Middleware) RequireForRoute

func (m *Middleware) RequireForRoute() forge.Middleware

RequireForRoute returns middleware that checks route-based rules

func (*Middleware) RequireLevel

func (m *Middleware) RequireLevel(level SecurityLevel) forge.Middleware

RequireLevel returns middleware that enforces a specific security level

type Plugin

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

Plugin implements the AuthSome plugin interface for step-up authentication

func NewPlugin

func NewPlugin(config *Config) *Plugin

NewPlugin creates a new step-up authentication plugin instance

func (*Plugin) Config

func (p *Plugin) Config() *Config

Config returns the plugin configuration

func (*Plugin) Description

func (p *Plugin) Description() string

Description returns the plugin description

func (*Plugin) Health

func (p *Plugin) Health(ctx context.Context) error

Health checks the plugin health

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique plugin identifier

func (*Plugin) Init

func (p *Plugin) Init(auth interface{}) error

Init initializes the plugin with the auth instance

func (*Plugin) Middleware

func (p *Plugin) Middleware() *Middleware

Middleware returns the step-up middleware (for route protection)

func (*Plugin) Migrate

func (p *Plugin) Migrate() error

Migrate creates required database tables and indexes

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the human-readable plugin name

func (*Plugin) RegisterHooks

func (p *Plugin) RegisterHooks(hookRegistry *hooks.HookRegistry) error

RegisterHooks registers step-up lifecycle hooks

func (*Plugin) RegisterRoutes

func (p *Plugin) RegisterRoutes(router forge.Router) error

RegisterRoutes registers HTTP routes for the plugin

func (*Plugin) RegisterServiceDecorators

func (p *Plugin) RegisterServiceDecorators(serviceRegistry *registry.ServiceRegistry) error

RegisterServiceDecorators allows step-up to enhance core services

func (*Plugin) Service

func (p *Plugin) Service() *Service

Service returns the step-up service (for programmatic access)

func (*Plugin) Shutdown

func (p *Plugin) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the plugin

func (*Plugin) StartCleanupScheduler

func (p *Plugin) StartCleanupScheduler(interval time.Duration)

StartCleanupScheduler starts a background task to cleanup expired records

func (*Plugin) Version

func (p *Plugin) Version() string

Version returns the plugin version

func (*Plugin) WithConfig

func (p *Plugin) WithConfig(config *Config) *Plugin

WithConfig sets custom configuration

type Repository

type Repository interface {
	// Verifications
	CreateVerification(ctx context.Context, verification *StepUpVerification) error
	GetVerification(ctx context.Context, id string) (*StepUpVerification, error)
	GetLatestVerification(ctx context.Context, userID, orgID string, level SecurityLevel) (*StepUpVerification, error)
	ListVerifications(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpVerification, error)

	// Requirements
	CreateRequirement(ctx context.Context, requirement *StepUpRequirement) error
	GetRequirement(ctx context.Context, id string) (*StepUpRequirement, error)
	GetRequirementByToken(ctx context.Context, token string) (*StepUpRequirement, error)
	UpdateRequirement(ctx context.Context, requirement *StepUpRequirement) error
	ListPendingRequirements(ctx context.Context, userID, orgID string) ([]*StepUpRequirement, error)
	DeleteExpiredRequirements(ctx context.Context) error

	// Remembered devices
	CreateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error
	GetRememberedDevice(ctx context.Context, userID, orgID, deviceID string) (*StepUpRememberedDevice, error)
	ListRememberedDevices(ctx context.Context, userID, orgID string) ([]*StepUpRememberedDevice, error)
	UpdateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error
	DeleteRememberedDevice(ctx context.Context, id string) error
	DeleteExpiredRememberedDevices(ctx context.Context) error

	// Attempts
	CreateAttempt(ctx context.Context, attempt *StepUpAttempt) error
	ListAttempts(ctx context.Context, requirementID string) ([]*StepUpAttempt, error)
	CountFailedAttempts(ctx context.Context, userID, orgID string, since time.Time) (int, error)

	// Policies
	CreatePolicy(ctx context.Context, policy *StepUpPolicy) error
	GetPolicy(ctx context.Context, id string) (*StepUpPolicy, error)
	ListPolicies(ctx context.Context, orgID string) ([]*StepUpPolicy, error)
	UpdatePolicy(ctx context.Context, policy *StepUpPolicy) error
	DeletePolicy(ctx context.Context, id string) error

	// Audit logs
	CreateAuditLog(ctx context.Context, log *StepUpAuditLog) error
	ListAuditLogs(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpAuditLog, error)
}

Repository defines the interface for step-up data persistence

type RequirementsResponse

type RequirementsResponse struct {
	Requirements interface{} `json:"requirements"`
	Count        int         `json:"count"`
}

type ResourceRule

type ResourceRule struct {
	ResourceType  string        `json:"resource_type" yaml:"resource_type"`   // Resource type (user, payment, etc.)
	Action        string        `json:"action" yaml:"action"`                 // Action (read, update, delete)
	SecurityLevel SecurityLevel `json:"security_level" yaml:"security_level"` // Required security level
	Sensitivity   string        `json:"sensitivity" yaml:"sensitivity"`       // Sensitivity classification
	Description   string        `json:"description" yaml:"description"`       // Human-readable description
	OrgID         string        `json:"org_id" yaml:"org_id"`                 // Organization-specific
}

ResourceRule defines step-up requirements based on resource types

type RouteRule

type RouteRule struct {
	Pattern       string        `json:"pattern" yaml:"pattern"`               // Route pattern (supports wildcards)
	Method        string        `json:"method" yaml:"method"`                 // HTTP method (GET, POST, etc.)
	SecurityLevel SecurityLevel `json:"security_level" yaml:"security_level"` // Required security level
	Description   string        `json:"description" yaml:"description"`       // Human-readable description
	OrgID         string        `json:"org_id" yaml:"org_id"`                 // Organization-specific (empty for global)
}

RouteRule defines step-up requirements based on route patterns

type SecurityLevel

type SecurityLevel string

SecurityLevel represents the strength of authentication required

const (
	SecurityLevelNone     SecurityLevel = "none"     // No step-up required
	SecurityLevelLow      SecurityLevel = "low"      // Recent login (within session)
	SecurityLevelMedium   SecurityLevel = "medium"   // Re-auth within time window
	SecurityLevelHigh     SecurityLevel = "high"     // Strong re-auth (password + 2FA)
	SecurityLevelCritical SecurityLevel = "critical" // Biometric or hardware token
)

type Service

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

Service handles step-up authentication business logic

func NewService

func NewService(repo Repository, config *Config, auditService AuditServiceInterface) *Service

NewService creates a new step-up service

func (*Service) CleanupExpired

func (s *Service) CleanupExpired(ctx context.Context) error

CleanupExpired removes expired requirements and devices

func (*Service) EvaluateRequirement

func (s *Service) EvaluateRequirement(ctx context.Context, evalCtx *EvaluationContext) (*EvaluationResult, error)

EvaluateRequirement evaluates whether step-up authentication is required

func (*Service) ForgetDevice

func (s *Service) ForgetDevice(ctx context.Context, userID, orgID, deviceID string) error

ForgetDevice removes a remembered device

func (*Service) VerifyStepUp

func (s *Service) VerifyStepUp(ctx context.Context, req *VerifyRequest) (*VerifyResponse, error)

VerifyStepUp verifies a step-up authentication attempt

type StatusResponse

type StatusResponse = responses.StatusResponse

type StepUpAttempt

type StepUpAttempt struct {
	ID            string             `bun:"id,pk" json:"id"`
	RequirementID string             `bun:"requirement_id,notnull" json:"requirement_id"`
	UserID        string             `bun:"user_id,notnull" json:"user_id"`
	OrgID         string             `bun:"org_id,notnull" json:"org_id"`
	Method        VerificationMethod `bun:"method,notnull" json:"method"`
	Success       bool               `bun:"success,notnull" json:"success"`
	FailureReason string             `bun:"failure_reason" json:"failure_reason,omitempty"`
	IP            string             `bun:"ip" json:"ip"`
	UserAgent     string             `bun:"user_agent" json:"user_agent"`
	CreatedAt     time.Time          `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
}

StepUpAttempt represents an attempt to complete step-up authentication

func (*StepUpAttempt) TableName

func (*StepUpAttempt) TableName() string

type StepUpAuditLog

type StepUpAuditLog struct {
	ID        string                 `bun:"id,pk" json:"id"`
	UserID    string                 `bun:"user_id,notnull" json:"user_id"`
	OrgID     string                 `bun:"org_id,notnull" json:"org_id"`
	EventType string                 `bun:"event_type,notnull" json:"event_type"`
	EventData map[string]interface{} `bun:"event_data,type:jsonb" json:"event_data"`
	IP        string                 `bun:"ip" json:"ip"`
	UserAgent string                 `bun:"user_agent" json:"user_agent"`
	Severity  string                 `bun:"severity,notnull" json:"severity"` // info, warning, critical
	CreatedAt time.Time              `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
}

StepUpAuditLog represents audit logs for step-up events

func (*StepUpAuditLog) TableName

func (*StepUpAuditLog) TableName() string

type StepUpAuditLogsResponse

type StepUpAuditLogsResponse struct {
	AuditLogs []interface{} `json:"audit_logs"`
}

type StepUpDevicesResponse

type StepUpDevicesResponse struct {
	Devices interface{} `json:"devices"`
	Count   int         `json:"count"`
}

type StepUpErrorResponse

type StepUpErrorResponse struct {
	Error string `json:"error" example:"Error message"`
}

DTOs for step-up routes

type StepUpEvaluationResponse

type StepUpEvaluationResponse struct {
	Required bool   `json:"required" example:"true"`
	Reason   string `json:"reason,omitempty" example:"High-value transaction"`
}

type StepUpPoliciesResponse

type StepUpPoliciesResponse struct {
	Policies []interface{} `json:"policies"`
}

type StepUpPolicy

type StepUpPolicy struct {
	ID          string                 `bun:"id,pk" json:"id"`
	OrgID       string                 `bun:"org_id,notnull" json:"org_id"`
	UserID      string                 `bun:"user_id" json:"user_id,omitempty"` // Optional: user-specific override
	Name        string                 `bun:"name,notnull" json:"name"`
	Description string                 `bun:"description" json:"description"`
	Enabled     bool                   `bun:"enabled,notnull,default:true" json:"enabled"`
	Priority    int                    `bun:"priority,notnull,default:0" json:"priority"` // Higher priority = evaluated first
	Rules       map[string]interface{} `bun:"rules,type:jsonb,notnull" json:"rules"`
	Metadata    map[string]interface{} `bun:"metadata,type:jsonb" json:"metadata,omitempty"`
	CreatedAt   time.Time              `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
	UpdatedAt   time.Time              `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}

StepUpPolicy represents an organization or user-specific step-up policy

func (*StepUpPolicy) TableName

func (*StepUpPolicy) TableName() string

type StepUpPolicyResponse

type StepUpPolicyResponse struct {
	ID string `json:"id" example:"policy_123"`
}

type StepUpRememberedDevice

type StepUpRememberedDevice struct {
	ID            string        `bun:"id,pk" json:"id"`
	UserID        string        `bun:"user_id,notnull" json:"user_id"`
	OrgID         string        `bun:"org_id,notnull" json:"org_id"`
	DeviceID      string        `bun:"device_id,notnull" json:"device_id"`
	DeviceName    string        `bun:"device_name" json:"device_name"`
	SecurityLevel SecurityLevel `bun:"security_level,notnull" json:"security_level"`
	IP            string        `bun:"ip" json:"ip"`
	UserAgent     string        `bun:"user_agent" json:"user_agent"`
	RememberedAt  time.Time     `bun:"remembered_at,notnull" json:"remembered_at"`
	ExpiresAt     time.Time     `bun:"expires_at,notnull" json:"expires_at"`
	LastUsedAt    time.Time     `bun:"last_used_at" json:"last_used_at"`
	CreatedAt     time.Time     `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
}

StepUpRememberedDevice represents a device that's remembered for step-up bypass

func (*StepUpRememberedDevice) TableName

func (*StepUpRememberedDevice) TableName() string

type StepUpRequirement

type StepUpRequirement struct {
	ID             string                 `bun:"id,pk" json:"id"`
	UserID         string                 `bun:"user_id,notnull" json:"user_id"`
	OrgID          string                 `bun:"org_id,notnull" json:"org_id"`
	SessionID      string                 `bun:"session_id" json:"session_id"`
	RequiredLevel  SecurityLevel          `bun:"required_level,notnull" json:"required_level"`
	CurrentLevel   SecurityLevel          `bun:"current_level,notnull" json:"current_level"`
	Route          string                 `bun:"route" json:"route"`
	Method         string                 `bun:"method" json:"method"`
	Amount         float64                `bun:"amount" json:"amount,omitempty"`
	Currency       string                 `bun:"currency" json:"currency,omitempty"`
	ResourceType   string                 `bun:"resource_type" json:"resource_type,omitempty"`
	ResourceAction string                 `bun:"resource_action" json:"resource_action,omitempty"`
	RuleName       string                 `bun:"rule_name" json:"rule_name"`
	Reason         string                 `bun:"reason" json:"reason"`
	Status         string                 `bun:"status,notnull" json:"status"` // pending, fulfilled, expired, bypassed
	ChallengeToken string                 `bun:"challenge_token" json:"challenge_token,omitempty"`
	IP             string                 `bun:"ip" json:"ip"`
	UserAgent      string                 `bun:"user_agent" json:"user_agent"`
	RiskScore      float64                `bun:"risk_score" json:"risk_score,omitempty"`
	Metadata       map[string]interface{} `bun:"metadata,type:jsonb" json:"metadata,omitempty"`
	CreatedAt      time.Time              `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
	ExpiresAt      time.Time              `bun:"expires_at,notnull" json:"expires_at"`
	FulfilledAt    *time.Time             `bun:"fulfilled_at" json:"fulfilled_at,omitempty"`
}

StepUpRequirement represents a step-up requirement record

func (*StepUpRequirement) TableName

func (*StepUpRequirement) TableName() string

type StepUpRequirementResponse

type StepUpRequirementResponse struct {
	ID string `json:"id" example:"req_123"`
}

type StepUpRequirementsResponse

type StepUpRequirementsResponse struct {
	Requirements []interface{} `json:"requirements"`
}

type StepUpStatusResponse

type StepUpStatusResponse struct {
	Status string `json:"status" example:"success"`
}

type StepUpVerification

type StepUpVerification struct {
	ID            string                 `bun:"id,pk" json:"id"`
	UserID        string                 `bun:"user_id,notnull" json:"user_id"`
	OrgID         string                 `bun:"org_id,notnull" json:"org_id"`
	SessionID     string                 `bun:"session_id" json:"session_id"`
	SecurityLevel SecurityLevel          `bun:"security_level,notnull" json:"security_level"`
	Method        VerificationMethod     `bun:"method,notnull" json:"method"`
	IP            string                 `bun:"ip" json:"ip"`
	UserAgent     string                 `bun:"user_agent" json:"user_agent"`
	DeviceID      string                 `bun:"device_id" json:"device_id"`
	Reason        string                 `bun:"reason" json:"reason"`       // Why step-up was required
	RuleName      string                 `bun:"rule_name" json:"rule_name"` // Which rule triggered
	VerifiedAt    time.Time              `bun:"verified_at,notnull" json:"verified_at"`
	ExpiresAt     time.Time              `bun:"expires_at,notnull" json:"expires_at"`
	Metadata      map[string]interface{} `bun:"metadata,type:jsonb" json:"metadata,omitempty"`
	CreatedAt     time.Time              `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
}

StepUpVerification represents a step-up authentication verification record

func (*StepUpVerification) TableName

func (*StepUpVerification) TableName() string

Table names

type StepUpVerificationResponse

type StepUpVerificationResponse struct {
	Verified  bool   `json:"verified" example:"true"`
	ExpiresAt string `json:"expires_at,omitempty" example:"2024-01-01T00:00:00Z"`
}

type StepUpVerificationsResponse

type StepUpVerificationsResponse struct {
	Verifications []interface{} `json:"verifications"`
}

type SuccessResponse

type SuccessResponse = responses.SuccessResponse

type TimeBasedRule

type TimeBasedRule struct {
	Operation     string        `json:"operation" yaml:"operation"`           // Operation name
	MaxAge        time.Duration `json:"max_age" yaml:"max_age"`               // Maximum age of authentication
	SecurityLevel SecurityLevel `json:"security_level" yaml:"security_level"` // Required security level
	Description   string        `json:"description" yaml:"description"`       // Human-readable description
	OrgID         string        `json:"org_id" yaml:"org_id"`                 // Organization-specific
}

TimeBasedRule defines step-up requirements based on time elapsed

type VerificationMethod

type VerificationMethod string

VerificationMethod represents acceptable verification methods

const (
	MethodPassword   VerificationMethod = "password"    // Password verification
	MethodTOTP       VerificationMethod = "totp"        // Time-based OTP
	MethodSMS        VerificationMethod = "sms"         // SMS code
	MethodEmail      VerificationMethod = "email"       // Email code
	MethodBiometric  VerificationMethod = "biometric"   // Biometric verification
	MethodWebAuthn   VerificationMethod = "webauthn"    // WebAuthn/FIDO2
	MethodBackupCode VerificationMethod = "backup_code" // Backup codes
)

type VerificationsResponse

type VerificationsResponse struct {
	Verifications interface{} `json:"verifications"`
	Count         int         `json:"count"`
}

type VerifyRequest

type VerifyRequest struct {
	RequirementID  string             `json:"requirement_id,omitempty"`
	ChallengeToken string             `json:"challenge_token,omitempty"`
	Method         VerificationMethod `json:"method"`
	Credential     string             `json:"credential"`
	RememberDevice bool               `json:"remember_device"`
	DeviceID       string             `json:"device_id,omitempty"`
	DeviceName     string             `json:"device_name,omitempty"`
	IP             string             `json:"ip,omitempty"`
	UserAgent      string             `json:"user_agent,omitempty"`
}

VerifyRequest contains the request to verify step-up authentication

type VerifyResponse

type VerifyResponse struct {
	Success          bool                   `json:"success"`
	VerificationID   string                 `json:"verification_id,omitempty"`
	SecurityLevel    SecurityLevel          `json:"security_level,omitempty"`
	ExpiresAt        time.Time              `json:"expires_at,omitempty"`
	Error            string                 `json:"error,omitempty"`
	DeviceRemembered bool                   `json:"device_remembered,omitempty"`
	Metadata         map[string]interface{} `json:"metadata,omitempty"`
}

VerifyResponse contains the response from verification

Jump to

Keyboard shortcuts

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