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 ¶
- Start Conservative - Begin with stricter rules, relax as needed
- Monitor Patterns - Review audit logs for optimization opportunities
- User Communication - Clearly explain why verification is required
- Graceful Degradation - Handle failures gracefully
- Test Thoroughly - Test all security levels and edge cases
- Regular Review - Review and update rules periodically
- 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 ¶
- GitHub: https://github.com/xraph/authsome
- Documentation: https://authsome.dev/docs/plugins/stepup
- Issues: https://github.com/xraph/authsome/issues
Index ¶
- Constants
- type AmountRule
- type AuditServiceInterface
- type BunRepository
- func (r *BunRepository) CountFailedAttempts(ctx context.Context, userID, orgID string, since time.Time) (int, error)
- func (r *BunRepository) CreateAttempt(ctx context.Context, attempt *StepUpAttempt) error
- func (r *BunRepository) CreateAuditLog(ctx context.Context, log *StepUpAuditLog) error
- func (r *BunRepository) CreatePolicy(ctx context.Context, policy *StepUpPolicy) error
- func (r *BunRepository) CreateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error
- func (r *BunRepository) CreateRequirement(ctx context.Context, requirement *StepUpRequirement) error
- func (r *BunRepository) CreateVerification(ctx context.Context, verification *StepUpVerification) error
- func (r *BunRepository) DeleteExpiredRememberedDevices(ctx context.Context) error
- func (r *BunRepository) DeleteExpiredRequirements(ctx context.Context) error
- func (r *BunRepository) DeletePolicy(ctx context.Context, id string) error
- func (r *BunRepository) DeleteRememberedDevice(ctx context.Context, id string) error
- func (r *BunRepository) GetLatestVerification(ctx context.Context, userID, orgID string, level SecurityLevel) (*StepUpVerification, error)
- func (r *BunRepository) GetPolicy(ctx context.Context, id string) (*StepUpPolicy, error)
- func (r *BunRepository) GetRememberedDevice(ctx context.Context, userID, orgID, deviceID string) (*StepUpRememberedDevice, error)
- func (r *BunRepository) GetRequirement(ctx context.Context, id string) (*StepUpRequirement, error)
- func (r *BunRepository) GetRequirementByToken(ctx context.Context, token string) (*StepUpRequirement, error)
- func (r *BunRepository) GetVerification(ctx context.Context, id string) (*StepUpVerification, error)
- func (r *BunRepository) ListAttempts(ctx context.Context, requirementID string) ([]*StepUpAttempt, error)
- func (r *BunRepository) ListAuditLogs(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpAuditLog, error)
- func (r *BunRepository) ListPendingRequirements(ctx context.Context, userID, orgID string) ([]*StepUpRequirement, error)
- func (r *BunRepository) ListPolicies(ctx context.Context, orgID string) ([]*StepUpPolicy, error)
- func (r *BunRepository) ListRememberedDevices(ctx context.Context, userID, orgID string) ([]*StepUpRememberedDevice, error)
- func (r *BunRepository) ListVerifications(ctx context.Context, userID, orgID string, limit, offset int) ([]*StepUpVerification, error)
- func (r *BunRepository) UpdatePolicy(ctx context.Context, policy *StepUpPolicy) error
- func (r *BunRepository) UpdateRememberedDevice(ctx context.Context, device *StepUpRememberedDevice) error
- func (r *BunRepository) UpdateRequirement(ctx context.Context, requirement *StepUpRequirement) error
- type Config
- type ContextRule
- type ErrorResponse
- type EvaluateRequest
- type EvaluationContext
- type EvaluationResult
- type ForgetDeviceResponse
- type Handler
- func (h *Handler) CreatePolicy(c forge.Context) error
- func (h *Handler) DeletePolicy(c forge.Context) error
- func (h *Handler) Evaluate(c forge.Context) error
- func (h *Handler) ForgetDevice(c forge.Context) error
- func (h *Handler) GetAuditLogs(c forge.Context) error
- func (h *Handler) GetPolicy(c forge.Context) error
- func (h *Handler) GetRequirement(c forge.Context) error
- func (h *Handler) ListPendingRequirements(c forge.Context) error
- func (h *Handler) ListPolicies(c forge.Context) error
- func (h *Handler) ListRememberedDevices(c forge.Context) error
- func (h *Handler) ListVerifications(c forge.Context) error
- func (h *Handler) Status(c forge.Context) error
- func (h *Handler) UpdatePolicy(c forge.Context) error
- func (h *Handler) Verify(c forge.Context) error
- type MessageResponse
- type Middleware
- func (m *Middleware) EvaluateMiddleware() forge.Middleware
- func (m *Middleware) RequireForAmount(amount float64, currency string) forge.Middleware
- func (m *Middleware) RequireForResource(resourceType, action string) forge.Middleware
- func (m *Middleware) RequireForRoute() forge.Middleware
- func (m *Middleware) RequireLevel(level SecurityLevel) forge.Middleware
- type Plugin
- func (p *Plugin) Config() *Config
- func (p *Plugin) Description() string
- func (p *Plugin) Health(ctx context.Context) error
- func (p *Plugin) ID() string
- func (p *Plugin) Init(auth interface{}) error
- func (p *Plugin) Middleware() *Middleware
- func (p *Plugin) Migrate() error
- func (p *Plugin) Name() string
- func (p *Plugin) RegisterHooks(hookRegistry *hooks.HookRegistry) error
- func (p *Plugin) RegisterRoutes(router forge.Router) error
- func (p *Plugin) RegisterServiceDecorators(serviceRegistry *registry.ServiceRegistry) error
- func (p *Plugin) Service() *Service
- func (p *Plugin) Shutdown(ctx context.Context) error
- func (p *Plugin) StartCleanupScheduler(interval time.Duration)
- func (p *Plugin) Version() string
- func (p *Plugin) WithConfig(config *Config) *Plugin
- type Repository
- type RequirementsResponse
- type ResourceRule
- type RouteRule
- type SecurityLevel
- type Service
- func (s *Service) CleanupExpired(ctx context.Context) error
- func (s *Service) EvaluateRequirement(ctx context.Context, evalCtx *EvaluationContext) (*EvaluationResult, error)
- func (s *Service) ForgetDevice(ctx context.Context, userID, orgID, deviceID string) error
- func (s *Service) VerifyStepUp(ctx context.Context, req *VerifyRequest) (*VerifyResponse, error)
- type StatusResponse
- type StepUpAttempt
- type StepUpAuditLog
- type StepUpAuditLogsResponse
- type StepUpDevicesResponse
- type StepUpErrorResponse
- type StepUpEvaluationResponse
- type StepUpPoliciesResponse
- type StepUpPolicy
- type StepUpPolicyResponse
- type StepUpRememberedDevice
- type StepUpRequirement
- type StepUpRequirementResponse
- type StepUpRequirementsResponse
- type StepUpStatusResponse
- type StepUpVerification
- type StepUpVerificationResponse
- type StepUpVerificationsResponse
- type SuccessResponse
- type TimeBasedRule
- type VerificationMethod
- type VerificationsResponse
- type VerifyRequest
- type VerifyResponse
Constants ¶
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 ¶
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 (*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
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 Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler handles step-up HTTP requests
func NewHandler ¶
NewHandler creates a new step-up handler
func (*Handler) CreatePolicy ¶
CreatePolicy handles POST /stepup/policies
func (*Handler) DeletePolicy ¶
DeletePolicy handles DELETE /stepup/policies/:id
func (*Handler) ForgetDevice ¶
ForgetDevice handles DELETE /stepup/devices/:id
func (*Handler) GetAuditLogs ¶
GetAuditLogs handles GET /stepup/audit
func (*Handler) GetRequirement ¶
GetRequirement handles GET /stepup/requirements/:id
func (*Handler) ListPendingRequirements ¶
ListPendingRequirements handles GET /stepup/requirements/pending
func (*Handler) ListPolicies ¶
ListPolicies handles GET /stepup/policies
func (*Handler) ListRememberedDevices ¶
ListRememberedDevices handles GET /stepup/devices
func (*Handler) ListVerifications ¶
ListVerifications handles GET /stepup/verifications
func (*Handler) UpdatePolicy ¶
UpdatePolicy handles PUT /stepup/policies/:id
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 (*Plugin) Description ¶
Description returns the plugin description
func (*Plugin) Middleware ¶
func (p *Plugin) Middleware() *Middleware
Middleware returns the step-up middleware (for route protection)
func (*Plugin) RegisterHooks ¶
func (p *Plugin) RegisterHooks(hookRegistry *hooks.HookRegistry) error
RegisterHooks registers step-up lifecycle hooks
func (*Plugin) RegisterRoutes ¶
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) StartCleanupScheduler ¶
StartCleanupScheduler starts a background task to cleanup expired records
func (*Plugin) WithConfig ¶
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 ¶
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 ¶
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 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
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