auth

package
v0.0.0-...-04478d6 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 52 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AnonUserID          = "00000000-0000-0000-0000-000000000000"
	ServiceUserID       = "00000000-0000-0000-0000-000000000001"
	TenantServiceUserID = "00000000-0000-0000-0000-000000000002"
)
View Source
const (
	// MinPasswordLength is the minimum required password length
	MinPasswordLength = 12 // Increased from 8 for better security
	// MaxPasswordLength is the maximum allowed password length (bcrypt limit is 72)
	MaxPasswordLength = 72
	// DefaultBcryptCost is the default cost for bcrypt hashing
	DefaultBcryptCost = 12
)
View Source
const (
	// Tables
	ScopeTablesRead  = "tables:read"
	ScopeTablesWrite = "tables:write"

	// Storage
	ScopeStorageRead  = "storage:read"
	ScopeStorageWrite = "storage:write"

	// Functions
	ScopeFunctionsRead    = "functions:read"
	ScopeFunctionsExecute = "functions:execute"

	// Auth
	ScopeAuthRead  = "auth:read"
	ScopeAuthWrite = "auth:write"

	// Client Keys
	ScopeClientKeysRead  = "clientkeys:read"
	ScopeClientKeysWrite = "clientkeys:write"

	// Webhooks
	ScopeWebhooksRead  = "webhooks:read"
	ScopeWebhooksWrite = "webhooks:write"

	// Monitoring
	ScopeMonitoringRead = "monitoring:read"

	// Realtime
	ScopeRealtimeConnect = "realtime:connect"

	// RPC
	ScopeRPCRead    = "rpc:read"
	ScopeRPCExecute = "rpc:execute"

	// Jobs
	ScopeJobsRead  = "jobs:read"
	ScopeJobsWrite = "jobs:write"

	// AI
	ScopeAIRead  = "ai:read"
	ScopeAIWrite = "ai:write"

	// Secrets
	ScopeSecretsRead  = "secrets:read"
	ScopeSecretsWrite = "secrets:write"

	// Migrations
	ScopeMigrationsRead    = "migrations:read"
	ScopeMigrationsExecute = "migrations:execute"

	// Wildcard scope grants all permissions
	ScopeWildcard = "*"
)

Scope constants for API key authorization

View Source
const (
	// Email validation
	MinEmailLength = 3   // Minimum is "a@b"
	MaxEmailLength = 254 // RFC 5321 limit

	// Name/display name validation
	MinNameLength = 1
	MaxNameLength = 100

	// Avatar URL validation
	MaxAvatarURLLength = 2048

	// General metadata limits
	MaxMetadataKeyLength   = 64
	MaxMetadataValueLength = 1024

	// Dashboard password validation (stricter than regular users)
	MinDashboardPasswordLength = 12
)

Validation constants for field limits

Variables

View Source
var (
	ErrCaptchaRequired      = errors.New("captcha verification required")
	ErrCaptchaInvalid       = errors.New("captcha verification failed")
	ErrCaptchaExpired       = errors.New("captcha token expired")
	ErrCaptchaNotConfigured = errors.New("captcha provider not configured")
	ErrCaptchaScoreTooLow   = errors.New("captcha score below threshold")
)

Common CAPTCHA errors

View Source
var (
	ErrChallengeNotFound = errors.New("challenge not found")
	ErrChallengeExpired  = errors.New("challenge expired")
	ErrChallengeConsumed = errors.New("challenge already consumed")
	ErrChallengeMismatch = errors.New("challenge context mismatch")
	ErrTrustTokenInvalid = errors.New("trust token invalid")
	ErrTrustTokenExpired = errors.New("trust token expired")
)

Trust-related errors

View Source
var (
	// ErrInvalidClientKey is returned when client key is invalid
	ErrInvalidClientKey = errors.New("invalid client key")
	// ErrClientKeyExpired is returned when client key has expired
	ErrClientKeyExpired = errors.New("client key has expired")
	// ErrClientKeyRevoked is returned when client key has been revoked
	ErrClientKeyRevoked = errors.New("client key has been revoked")
	// ErrUserClientKeysDisabled is returned when user client keys are disabled via settings
	ErrUserClientKeysDisabled = errors.New("user client keys are disabled")
)
View Source
var (
	// ErrEmailVerificationTokenNotFound is returned when a token is not found
	ErrEmailVerificationTokenNotFound = errors.New("email verification token not found")
	// ErrEmailVerificationTokenExpired is returned when a token has expired
	ErrEmailVerificationTokenExpired = errors.New("email verification token has expired")
	// ErrEmailVerificationTokenUsed is returned when a token has already been used
	ErrEmailVerificationTokenUsed = errors.New("email verification token has already been used")
	// ErrEmailNotVerified is returned when a user's email is not verified but verification is required
	ErrEmailNotVerified = errors.New("email not verified")
)
View Source
var (
	// ErrIdentityNotFound is returned when an identity is not found
	ErrIdentityNotFound = errors.New("identity not found")
	// ErrIdentityAlreadyLinked is returned when trying to link an identity that's already linked
	ErrIdentityAlreadyLinked = errors.New("identity is already linked to another user")
)
View Source
var (
	ErrNotAdmin              = errors.New("only dashboard admins can impersonate users")
	ErrSelfImpersonation     = errors.New("cannot impersonate yourself")
	ErrNoActiveImpersonation = errors.New("no active impersonation session found")
	ErrTenantRequired        = errors.New("tenant context is required for impersonation")
	ErrTargetUserNotInTenant = errors.New("target user does not belong to the current tenant")
	ErrNotTenantAdmin        = errors.New("user is not an admin for the specified tenant")
)
View Source
var (
	// ErrInvitationNotFound is returned when an invitation token is not found
	ErrInvitationNotFound = errors.New("invitation not found")
	// ErrInvitationExpired is returned when an invitation token has expired
	ErrInvitationExpired = errors.New("invitation has expired")
	// ErrInvitationAlreadyAccepted is returned when an invitation has already been accepted
	ErrInvitationAlreadyAccepted = errors.New("invitation has already been accepted")
)
View Source
var (
	// ErrInvalidToken is returned when a token is invalid
	ErrInvalidToken = errors.New("invalid token")
	// ErrExpiredToken is returned when a token has expired
	ErrExpiredToken = errors.New("token has expired")
	// ErrInvalidSignature is returned when token signature is invalid
	ErrInvalidSignature = errors.New("invalid token signature")
)
View Source
var (
	// ErrMagicLinkNotFound is returned when a magic link is not found
	ErrMagicLinkNotFound = errors.New("magic link not found")
	// ErrMagicLinkExpired is returned when a magic link has expired
	ErrMagicLinkExpired = errors.New("magic link has expired")
	// ErrMagicLinkUsed is returned when a magic link has already been used
	ErrMagicLinkUsed = errors.New("magic link has already been used")
)
View Source
var (
	// ErrInvalidProvider is returned when an OAuth provider is not supported
	ErrInvalidProvider = errors.New("invalid OAuth provider")
	// ErrInvalidState is returned when OAuth state doesn't match
	ErrInvalidState = errors.New("invalid OAuth state")
)
View Source
var (
	// ErrOAuthLogoutStateNotFound is returned when a logout state is not found
	ErrOAuthLogoutStateNotFound = errors.New("oauth logout state not found")
	// ErrOAuthLogoutStateExpired is returned when a logout state has expired
	ErrOAuthLogoutStateExpired = errors.New("oauth logout state expired")
	// ErrOAuthTokenNotFound is returned when no OAuth token is found for the user/provider
	ErrOAuthTokenNotFound = errors.New("oauth token not found")
	// ErrOAuthProviderNoSLO is returned when the provider doesn't support logout
	ErrOAuthProviderNoSLO = errors.New("oauth provider does not support single logout")
)
View Source
var (
	// ErrOTPNotFound is returned when an OTP code is not found
	ErrOTPNotFound = errors.New("otp code not found")
	// ErrOTPExpired is returned when an OTP code has expired
	ErrOTPExpired = errors.New("otp code has expired")
	// ErrOTPUsed is returned when an OTP code has already been used
	ErrOTPUsed = errors.New("otp code has already been used")
	// ErrOTPInvalid is returned when an OTP code is invalid
	ErrOTPInvalid = errors.New("otp code is invalid")
	// ErrOTPMaxAttemptsExceeded is returned when max verification attempts are exceeded
	ErrOTPMaxAttemptsExceeded = errors.New("maximum otp verification attempts exceeded")
)
View Source
var (
	// ErrWeakPassword is returned when a password doesn't meet minimum requirements
	ErrWeakPassword = errors.New("password does not meet minimum requirements")
	// ErrPasswordTooLong is returned when password exceeds maximum length
	ErrPasswordTooLong = errors.New("password exceeds maximum length")
)
View Source
var (
	// ErrPasswordResetTokenNotFound is returned when a password reset token is not found
	ErrPasswordResetTokenNotFound = errors.New("password reset token not found")
	// ErrPasswordResetTokenExpired is returned when a password reset token has expired
	ErrPasswordResetTokenExpired = errors.New("password reset token has expired")
	// ErrPasswordResetTokenUsed is returned when a password reset token has already been used
	ErrPasswordResetTokenUsed = errors.New("password reset token has already been used")
	// ErrSMTPNotConfigured is returned when attempting password reset without SMTP configured
	ErrSMTPNotConfigured = errors.New("SMTP is not configured")
	// ErrEmailSendFailed is returned when the password reset email could not be sent
	ErrEmailSendFailed = errors.New("failed to send password reset email")
	// ErrInvalidRedirectURL is returned when the redirect URL is not a valid URL
	ErrInvalidRedirectURL = errors.New("invalid redirect URL: must be a valid HTTP or HTTPS URL")
	// ErrPasswordResetTooSoon is returned when a password reset was requested too recently
	ErrPasswordResetTooSoon = errors.New("password reset requested too recently, please wait before trying again")
)
View Source
var (
	ErrSAMLProviderNotFound     = errors.New("SAML provider not found")
	ErrSAMLProviderDisabled     = errors.New("SAML provider is disabled")
	ErrSAMLMetadataFetchFailed  = errors.New("failed to fetch IdP metadata")
	ErrSAMLMetadataParseFailed  = errors.New("failed to parse IdP metadata")
	ErrSAMLMetadataInsecureURL  = errors.New("SAML metadata URL must use HTTPS")
	ErrSAMLAssertionInvalid     = errors.New("invalid SAML assertion")
	ErrSAMLAssertionExpired     = errors.New("SAML assertion has expired")
	ErrSAMLAssertionReplayed    = errors.New("SAML assertion has already been used")
	ErrSAMLAudienceMismatch     = errors.New("SAML assertion audience does not match service provider")
	ErrSAMLMissingEmail         = errors.New("email attribute not found in SAML assertion")
	ErrSAMLUserCreationDisabled = errors.New("automatic user creation is disabled for this provider")
	ErrSAMLInvalidRelayState    = errors.New("invalid RelayState redirect URL")

	// SLO errors
	ErrSAMLSLONotSupported       = errors.New("SAML SLO not supported by this provider")
	ErrSAMLSessionNotFound       = errors.New("SAML session not found")
	ErrSAMLLogoutFailed          = errors.New("SAML logout failed")
	ErrSAMLInvalidLogoutRequest  = errors.New("invalid SAML LogoutRequest")
	ErrSAMLInvalidLogoutResponse = errors.New("invalid SAML LogoutResponse")
	ErrSAMLSigningKeyMissing     = errors.New("SP signing key not configured")
)
View Source
var (
	// ErrSessionNotFound is returned when a session is not found
	ErrSessionNotFound = errors.New("session not found")
	// ErrSessionExpired is returned when a session has expired
	ErrSessionExpired = errors.New("session has expired")
)
View Source
var (
	// ErrUserNotFound is returned when a user is not found
	ErrUserNotFound = errors.New("user not found")
	// ErrUserAlreadyExists is returned when trying to create a user with existing email
	ErrUserAlreadyExists = errors.New("user with this email already exists")
	// ErrInvalidCredentials is returned when login credentials are invalid
	ErrInvalidCredentials = errors.New("invalid email or password")
	// ErrAccountLocked is returned when an account is locked due to too many failed login attempts
	ErrAccountLocked = errors.New("account locked due to too many failed login attempts")
)
View Source
var (
	// ErrInvalidEmail is returned when email format is invalid
	ErrInvalidEmail = errors.New("invalid email address")
	// ErrEmailTooLong is returned when email exceeds max length
	ErrEmailTooLong = errors.New("email address is too long (max 254 characters)")
	// ErrEmailTooShort is returned when email is too short
	ErrEmailTooShort = errors.New("email address is too short")
	// ErrNameTooLong is returned when name exceeds max length
	ErrNameTooLong = errors.New("name is too long (max 100 characters)")
	// ErrNameTooShort is returned when name is empty
	ErrNameTooShort = errors.New("name is required")
	// ErrAvatarURLTooLong is returned when avatar URL exceeds max length
	ErrAvatarURLTooLong = errors.New("avatar URL is too long (max 2048 characters)")
	// ErrInvalidAvatarURL is returned when avatar URL format is invalid
	ErrInvalidAvatarURL = errors.New("invalid avatar URL format")
	// ErrDashboardPasswordTooShort is returned when dashboard password is too short
	ErrDashboardPasswordTooShort = errors.New("password must be at least 12 characters long")
	// ErrOTPContactRequired is returned when neither email nor phone is provided for OTP
	ErrOTPContactRequired = errors.New("either email or phone must be provided")
	// ErrInvalidDashboardRole is returned when an invalid dashboard role is provided
	ErrInvalidDashboardRole = errors.New("invalid role. Must be 'instance_admin' or 'tenant_admin'")
)

AllScopes contains all valid scopes (excluding wildcard)

View Source
var ErrCannotRevokeClientKey = errors.New("cannot blacklist client keys - use revoke endpoint instead")

ErrCannotRevokeClientKey is returned when attempting to blacklist a client key

View Source
var ErrCannotRevokeServiceKey = errors.New("cannot blacklist service keys - use disable endpoint instead")

ErrCannotRevokeServiceKey is returned when attempting to blacklist a service key

View Source
var ErrCannotRevokeServiceRole = errors.New("cannot revoke service role tokens")

ErrCannotRevokeServiceRole is returned when attempting to revoke a service role token

View Source
var ErrInstanceSettingNotFound = errors.New("instance-level setting not found")

ErrInstanceSettingNotFound is returned when an instance-level setting is not found

View Source
var ErrSettingNotFound = errors.New("system setting not found")

ErrSettingNotFound is returned when a system setting is not found

View Source
var ErrTOTPRateLimitExceeded = errors.New("too many 2FA attempts, please try again later")

ErrTOTPRateLimitExceeded is returned when a user has exceeded the TOTP attempt limit

View Source
var ErrTenantSettingNotFound = errors.New("tenant-level setting not found")

ErrTenantSettingNotFound is returned when a tenant-level setting is not found

View Source
var ErrTokenBlacklisted = errors.New("token has been revoked")

ErrTokenBlacklisted is returned when a token is found in the blacklist

View Source
var ValidDashboardRoles = []string{"instance_admin", "tenant_admin"}

ValidDashboardRoles contains the valid roles for dashboard users

Functions

func ExtractAllowedNamespaces

func ExtractAllowedNamespaces(scopes []string, resource string) []string

ExtractAllowedNamespaces derives the list of allowed namespaces from scopes for a specific resource type.

Parameters:

  • scopes: List of scope strings
  • resource: The resource type to check (e.g., "functions", "rpc", "jobs")

Returns:

  • nil: All namespaces allowed (wildcard or no restrictions)
  • []string{}: Only default namespace allowed
  • []string{"prod", "dev"}: Specific namespaces allowed

Note: This function returns explicit namespace lists, not patterns. Wildcard patterns (e.g., "prod-*") in scopes will result in nil (all allowed).

func GenerateBackupCodes

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

GenerateBackupCodes generates a set of backup codes for 2FA recovery Returns both the plain codes (to show to user) and hashed codes (to store)

func GenerateLogoutState

func GenerateLogoutState() (string, error)

GenerateLogoutState generates a random state for CSRF protection during logout

func GenerateMagicLinkToken

func GenerateMagicLinkToken() (string, error)

GenerateMagicLinkToken generates a secure random token for magic links

func GenerateOTPCode

func GenerateOTPCode(length int) (string, error)

GenerateOTPCode generates a secure random numeric OTP code

func GeneratePasswordResetToken

func GeneratePasswordResetToken() (string, error)

GeneratePasswordResetToken generates a secure random token for password resets

func GenerateState

func GenerateState() (string, error)

GenerateState generates a random state parameter for CSRF protection

func GenerateTOTPSecret

func GenerateTOTPSecret(issuer, accountName string) (string, string, string, error)

GenerateTOTPSecret generates a new TOTP secret, QR code image, and otpauth URI Returns: secret (base32), qrCodeDataURI (base64 PNG data URI), otpauthURI, error

func GetDefaultEndSessionEndpoint

func GetDefaultEndSessionEndpoint(provider OAuthProvider) string

GetDefaultEndSessionEndpoint returns the default OIDC end_session_endpoint for known providers

func GetDefaultRevocationEndpoint

func GetDefaultRevocationEndpoint(provider OAuthProvider) string

GetDefaultRevocationEndpoint returns the default revocation endpoint for known providers

func HasAllScopes

func HasAllScopes(scopes []string, required []string) bool

HasAllScopes checks if a list of scopes contains all required scopes Returns true if all required scopes are present (or if wildcard is present)

func HasScope

func HasScope(scopes []string, required string) bool

HasScope checks if a list of scopes contains the required scope Returns true if the scopes contain the required scope or the wildcard scope

func HasScopeForNamespace

func HasScopeForNamespace(scopes []string, action, resource, namespace string) bool

HasScopeForNamespace checks if the given scopes grant access to a specific resource in a specific namespace.

Parameters:

  • scopes: List of scope strings (e.g., ["execute:functions:prod", "tables:read"])
  • action: The action being performed (e.g., "execute", "read", "write")
  • resource: The resource type (e.g., "functions", "rpc", "jobs")
  • namespace: The specific namespace to check access for

Returns true if any scope grants access to the resource in the namespace.

func IsNamespaceAllowed

func IsNamespaceAllowed(namespace string, allowedNamespaces []string) bool

IsNamespaceAllowed checks if a namespace is in the allowed list. Helper function for filtering operations.

Parameters:

  • namespace: The namespace to check
  • allowedNamespaces: The list of allowed namespaces (nil = all allowed)

Returns true if the namespace is allowed.

func IsValidScope

func IsValidScope(scope string) bool

IsValidScope checks if a single scope is valid

func LogSecurityEvent

func LogSecurityEvent(ctx context.Context, event SecurityEvent)

LogSecurityEvent logs a security event using the global logger

func LogSecurityWarning

func LogSecurityWarning(ctx context.Context, event SecurityEvent)

LogSecurityWarning logs a warning-level security event using the global logger

func MatchNamespacePattern

func MatchNamespacePattern(namespace, pattern string) bool

MatchNamespacePattern checks if a namespace matches a pattern. Patterns supported:

  • "*" → matches all namespaces
  • "prod" → exact match only
  • "prod-*" → prefix match (namespaces starting with "prod-")

Note: Only prefix wildcards are supported to prevent ReDoS attacks.

func ParseNamespaceScope

func ParseNamespaceScope(scope string) (action, resource, namespacePattern string)

ParseNamespaceScope parses a scope into its component parts. Scope format: "resource:action:namespace_pattern" Examples:

  • "*" → ("*", "*", "*")
  • "tables:read" → ("read", "tables", "*")
  • "functions:execute:prod" → ("execute", "functions", "prod")
  • "functions:execute:prod-*" → ("execute", "functions", "prod-*")

Returns: action, resource, namespacePattern

func SanitizeSAMLAttribute

func SanitizeSAMLAttribute(value string) string

SanitizeSAMLAttribute cleans a SAML attribute value for safe storage and display This prevents XSS attacks from malicious IdP attribute values

func ValidateAvatarURL

func ValidateAvatarURL(url string) error

ValidateAvatarURL validates an avatar URL

func ValidateDashboardPassword

func ValidateDashboardPassword(password string) error

ValidateDashboardPassword validates password strength for dashboard/admin users Dashboard users have stricter requirements (12 chars) than regular users (8 chars)

func ValidateDashboardRole

func ValidateDashboardRole(role string) error

ValidateDashboardRole validates that a role is valid for dashboard users

func ValidateEmail

func ValidateEmail(email string) error

ValidateEmail validates an email address for format and length

func ValidateName

func ValidateName(name string) error

ValidateName validates a name field (full name, display name, etc.)

func ValidateNameOptional

func ValidateNameOptional(name string) error

ValidateNameOptional validates a name field that can be empty

func ValidateOAuthClaims

func ValidateOAuthClaims(provider *OAuthProviderRBAC, idTokenClaims map[string]interface{}) error

ValidateOAuthClaims validates user's OAuth ID token claims against provider's RBAC rules

func ValidateOTPContact

func ValidateOTPContact(email, phone *string) error

ValidateOTPContact validates that either email or phone is provided for OTP operations

func ValidateRelayState

func ValidateRelayState(relayState string, allowedHosts []string) (string, error)

ValidateRelayState validates that a RelayState URL is safe for redirect Returns the validated URL or an error if the URL is not allowed

func ValidateScopes

func ValidateScopes(scopes []string) error

ValidateScopes checks if all provided scopes are valid Returns an error if any scope is invalid or if no scopes are provided

func VerifyBackupCode

func VerifyBackupCode(code, hashedCode string) (bool, error)

VerifyBackupCode verifies a backup code against its hash

func VerifyTOTPCode

func VerifyTOTPCode(code, secret string) (bool, error)

VerifyTOTPCode verifies a TOTP code against a secret

Types

type CapProvider

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

CapProvider implements CAPTCHA verification using Cap (self-hosted proof-of-work CAPTCHA) Cap is a privacy-first, self-hosted CAPTCHA solution that uses proof-of-work challenges instead of visual puzzles. See: https://capjs.js.org/

func NewCapProvider

func NewCapProvider(serverURL, apiKey string, httpClient *http.Client) (*CapProvider, error)

NewCapProvider creates a new Cap provider with SSRF protection. Returns an error if the server URL is invalid or points to a private/internal address.

func (*CapProvider) Name

func (p *CapProvider) Name() string

Name returns the provider name

func (*CapProvider) Verify

func (p *CapProvider) Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

Verify validates a Cap response token

type CaptchaChallenge

type CaptchaChallenge struct {
	ID                string
	ChallengeID       string
	Endpoint          string
	Email             string
	IPAddress         string
	DeviceFingerprint string
	UserAgent         string
	TrustScore        int
	CaptchaRequired   bool
	Reason            string
	CreatedAt         time.Time
	ExpiresAt         time.Time
	ConsumedAt        *time.Time
	CaptchaVerified   bool
}

CaptchaChallenge represents a stored challenge

type CaptchaCheckRequest

type CaptchaCheckRequest struct {
	Endpoint          string `json:"endpoint"`
	Email             string `json:"email,omitempty"`
	DeviceFingerprint string `json:"device_fingerprint,omitempty"`
	TrustToken        string `json:"trust_token,omitempty"`
}

CaptchaCheckRequest is the API request for checking if CAPTCHA is required

type CaptchaCheckResponse

type CaptchaCheckResponse struct {
	CaptchaRequired bool   `json:"captcha_required"`
	Reason          string `json:"reason,omitempty"`
	TrustScore      int    `json:"trust_score,omitempty"`

	// Widget configuration (only if captcha_required=true)
	Provider string `json:"provider,omitempty"`
	SiteKey  string `json:"site_key,omitempty"`

	// Challenge tracking
	ChallengeID string `json:"challenge_id"`
	ExpiresAt   string `json:"expires_at"`
}

CaptchaCheckResponse is the API response for CAPTCHA check

type CaptchaConfigResponse

type CaptchaConfigResponse struct {
	Enabled      bool     `json:"enabled"`
	Provider     string   `json:"provider,omitempty"`
	SiteKey      string   `json:"site_key,omitempty"`
	Endpoints    []string `json:"endpoints,omitempty"`
	CapServerURL string   `json:"cap_server_url,omitempty"` // Cap provider: URL for widget to load from
}

CaptchaConfigResponse is the public configuration returned to clients

type CaptchaProvider

type CaptchaProvider interface {
	// Verify validates a CAPTCHA token and returns the verification result
	// remoteIP is the client's IP address (used for additional validation)
	Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

	// Name returns the provider name (hcaptcha, recaptcha_v3, turnstile)
	Name() string
}

CaptchaProvider defines the interface for CAPTCHA verification providers

type CaptchaResult

type CaptchaResult struct {
	Success   bool      `json:"success"`
	Score     float64   `json:"score,omitempty"`     // Risk score (0.0-1.0, only for reCAPTCHA v3)
	Action    string    `json:"action,omitempty"`    // Action name (only for reCAPTCHA v3)
	Hostname  string    `json:"hostname,omitempty"`  // Hostname where the challenge was solved
	Timestamp time.Time `json:"timestamp,omitempty"` // When the challenge was solved
	ErrorCode string    `json:"error_code,omitempty"`
}

CaptchaResult contains the result of a CAPTCHA verification

type CaptchaService

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

CaptchaService manages CAPTCHA verification across different providers

func NewCaptchaService

func NewCaptchaService(cfg *config.CaptchaConfig) (*CaptchaService, error)

NewCaptchaService creates a new CAPTCHA service based on configuration

func NewDisabledCaptchaService

func NewDisabledCaptchaService() *CaptchaService

NewDisabledCaptchaService creates a CaptchaService that is disabled for testing.

func NewMockCaptchaService

func NewMockCaptchaService(cfg *config.CaptchaConfig, provider CaptchaProvider) *CaptchaService

NewMockCaptchaService creates a CaptchaService with a mock provider for testing. This is useful for integration tests that need to test handler behavior with captcha.

func NewTestCaptchaService

func NewTestCaptchaService(endpoints []string, validToken string) *CaptchaService

NewTestCaptchaService creates a CaptchaService configured for testing. It creates a service that: - Requires captcha for the specified endpoints - Returns ErrCaptchaRequired for empty tokens - Returns ErrCaptchaInvalid for tokens other than validToken - Returns success for validToken

func (*CaptchaService) GetConfig

func (s *CaptchaService) GetConfig() CaptchaConfigResponse

GetConfig returns the public CAPTCHA configuration for clients

func (*CaptchaService) GetProvider

func (s *CaptchaService) GetProvider() string

GetProvider returns the configured provider name

func (*CaptchaService) GetSiteKey

func (s *CaptchaService) GetSiteKey() string

GetSiteKey returns the public site key (safe to expose to frontend)

func (*CaptchaService) IsEnabled

func (s *CaptchaService) IsEnabled() bool

IsEnabled returns whether CAPTCHA verification is enabled

func (*CaptchaService) IsEnabledForEndpoint

func (s *CaptchaService) IsEnabledForEndpoint(endpoint string) bool

IsEnabledForEndpoint checks if CAPTCHA is enabled for a specific endpoint

func (*CaptchaService) ReloadFromSettings

func (s *CaptchaService) ReloadFromSettings(ctx context.Context, settingsCache *SettingsCache, envConfig *config.SecurityConfig) error

ReloadFromSettings reloads the captcha configuration from database settings Priority order: Config/Env → Database

func (*CaptchaService) Verify

func (s *CaptchaService) Verify(ctx context.Context, token string, remoteIP string) error

Verify validates a CAPTCHA token Returns nil if verification succeeds, or an error if it fails

func (*CaptchaService) VerifyForEndpoint

func (s *CaptchaService) VerifyForEndpoint(ctx context.Context, endpoint, token, remoteIP string) error

VerifyForEndpoint validates CAPTCHA for a specific endpoint Only verifies if the endpoint is configured to require CAPTCHA

type CaptchaTrustService

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

CaptchaTrustService handles adaptive CAPTCHA trust evaluation

func NewCaptchaTrustService

func NewCaptchaTrustService(db *database.Connection, captchaConfig *config.CaptchaConfig, captchaService *CaptchaService) *CaptchaTrustService

NewCaptchaTrustService creates a new trust service

func (*CaptchaTrustService) CalculateTrust

func (s *CaptchaTrustService) CalculateTrust(ctx context.Context, req TrustRequest) (*TrustResult, error)

CalculateTrust evaluates trust signals and returns a trust result

func (*CaptchaTrustService) CheckCaptchaRequired

func (s *CaptchaTrustService) CheckCaptchaRequired(ctx context.Context, req CaptchaCheckRequest, ipAddress, userAgent string) (*CaptchaCheckResponse, error)

CheckCaptchaRequired evaluates trust and creates a challenge

func (*CaptchaTrustService) GetChallenge

func (s *CaptchaTrustService) GetChallenge(ctx context.Context, challengeID string) (*CaptchaChallenge, error)

GetChallenge retrieves a challenge by ID

func (*CaptchaTrustService) IsEnabled

func (s *CaptchaTrustService) IsEnabled() bool

IsEnabled returns whether adaptive trust is enabled

func (*CaptchaTrustService) IssueTrustToken

func (s *CaptchaTrustService) IssueTrustToken(ctx context.Context, ipAddress, deviceFingerprint, userAgent string) (string, error)

IssueTrustToken creates a trust token after successful CAPTCHA verification

func (*CaptchaTrustService) RecordCaptchaSolved

func (s *CaptchaTrustService) RecordCaptchaSolved(ctx context.Context, userID *uuid.UUID, ipAddress, deviceFingerprint, userAgent string) error

RecordCaptchaSolved updates trust signals after a successful CAPTCHA

func (*CaptchaTrustService) RecordFailedAttempt

func (s *CaptchaTrustService) RecordFailedAttempt(ctx context.Context, userID *uuid.UUID, ipAddress, deviceFingerprint, userAgent string) error

RecordFailedAttempt updates trust signals after a failed login attempt

func (*CaptchaTrustService) RecordSuccessfulLogin

func (s *CaptchaTrustService) RecordSuccessfulLogin(ctx context.Context, userID uuid.UUID, ipAddress, deviceFingerprint, userAgent string) error

RecordSuccessfulLogin updates trust signals after a successful login

func (*CaptchaTrustService) ValidateChallenge

func (s *CaptchaTrustService) ValidateChallenge(ctx context.Context, challengeID, endpoint, ipAddress string, captchaVerified bool) error

ValidateChallenge checks if a challenge is valid and optionally consumes it

func (*CaptchaTrustService) ValidateTrustToken

func (s *CaptchaTrustService) ValidateTrustToken(ctx context.Context, token, ipAddress, deviceFingerprint string) (bool, error)

ValidateTrustToken checks if a trust token is valid

type ClientKey

type ClientKey struct {
	ID                 uuid.UUID  `json:"id"`
	Name               string     `json:"name"`
	Description        *string    `json:"description,omitempty"`
	KeyHash            string     `json:"-"` // Never expose the hash
	KeyPrefix          string     `json:"key_prefix"`
	UserID             *uuid.UUID `json:"user_id,omitempty"`
	Scopes             []string   `json:"scopes"`
	AllowedNamespaces  []string   `json:"allowed_namespaces,omitempty"` // nil = all namespaces, empty = default only
	RateLimitPerMinute int        `json:"rate_limit_per_minute"`
	LastUsedAt         *time.Time `json:"last_used_at,omitempty"`
	ExpiresAt          *time.Time `json:"expires_at,omitempty"`
	RevokedAt          *time.Time `json:"revoked_at,omitempty"`
	CreatedAt          time.Time  `json:"created_at"`
	UpdatedAt          time.Time  `json:"updated_at"`
}

ClientKey represents a client key

type ClientKeyService

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

ClientKeyService handles client key operations

func NewClientKeyService

func NewClientKeyService(db *database.Connection, settingsCache *SettingsCache) *ClientKeyService

NewClientKeyService creates a new client key service

func (*ClientKeyService) DeleteClientKey

func (s *ClientKeyService) DeleteClientKey(ctx context.Context, id uuid.UUID) error

DeleteClientKey permanently deletes a client key

func (*ClientKeyService) GenerateClientKey

func (s *ClientKeyService) GenerateClientKey(ctx context.Context, name string, description *string, userID *uuid.UUID, scopes []string, rateLimitPerMinute int, expiresAt *time.Time) (*ClientKeyWithPlaintext, error)

GenerateClientKey generates a new client key with format: fbk_<random_string>

func (*ClientKeyService) ListClientKeys

func (s *ClientKeyService) ListClientKeys(ctx context.Context, userID *uuid.UUID) ([]ClientKey, error)

ListClientKeys lists all client keys (optionally filtered by user and tenant)

func (*ClientKeyService) RevokeClientKey

func (s *ClientKeyService) RevokeClientKey(ctx context.Context, id uuid.UUID) error

RevokeClientKey revokes a client key

func (*ClientKeyService) SetSettingsCache

func (s *ClientKeyService) SetSettingsCache(cache *SettingsCache)

SetSettingsCache injects the settings cache after initialization This is used to break the circular dependency during server startup

func (*ClientKeyService) UpdateClientKey

func (s *ClientKeyService) UpdateClientKey(ctx context.Context, id uuid.UUID, name *string, description *string, scopes []string, rateLimitPerMinute *int) error

UpdateClientKey updates a client key's metadata

func (*ClientKeyService) ValidateClientKey

func (s *ClientKeyService) ValidateClientKey(ctx context.Context, plaintextKey string) (*ClientKey, error)

ValidateClientKey validates a client key and returns the associated client key info

type ClientKeyWithPlaintext

type ClientKeyWithPlaintext struct {
	ClientKey
	PlaintextKey string `json:"key"` // Full key, only shown once
}

ClientKeyWithPlaintext includes the plaintext key (only returned once during creation)

type CreateUserRequest

type CreateUserRequest struct {
	Email        string `json:"email"`
	Password     string `json:"password"`
	Role         string `json:"role,omitempty"`
	UserMetadata any    `json:"user_metadata,omitempty"` // User-editable metadata
	AppMetadata  any    `json:"app_metadata,omitempty"`  // Application/admin-only metadata
}

CreateUserRequest represents a request to create a new user

type DBStateStore

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

DBStateStore provides database-backed OAuth state storage Supports multi-instance deployments where OAuth callback may hit different instance

func NewDBStateStore

func NewDBStateStore(db *database.Connection, config DBStateStoreConfig) *DBStateStore

NewDBStateStore creates a new database-backed state store

func (*DBStateStore) Cleanup

func (s *DBStateStore) Cleanup(ctx context.Context) error

Cleanup removes expired state tokens from the database

func (*DBStateStore) GetAndValidate

func (s *DBStateStore) GetAndValidate(ctx context.Context, state string) (*StateMetadata, bool)

GetAndValidate validates a state token, removes it, and returns the metadata

func (*DBStateStore) Set

func (s *DBStateStore) Set(ctx context.Context, state string, metadata StateMetadata) error

Set stores a state token with metadata in the database

func (*DBStateStore) Stop

func (s *DBStateStore) Stop()

Stop stops the cleanup goroutine

func (*DBStateStore) Validate

func (s *DBStateStore) Validate(ctx context.Context, state string) bool

Validate checks if a state token is valid and removes it

type DBStateStoreConfig

type DBStateStoreConfig struct {
	// DefaultTTL is the default time-to-live for state tokens (default: 10 minutes)
	DefaultTTL time.Duration
	// CleanupInterval is how often to run cleanup (default: 5 minutes)
	CleanupInterval time.Duration
}

DBStateStoreConfig holds configuration for database-backed state storage

func DefaultDBStateStoreConfig

func DefaultDBStateStoreConfig() DBStateStoreConfig

DefaultDBStateStoreConfig returns the default configuration

type DashboardAuthService

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

DashboardAuthService handles authentication for dashboard administrators

func NewDashboardAuthService

func NewDashboardAuthService(db *database.Connection, jwtManager *JWTManager, totpIssuer string) *DashboardAuthService

NewDashboardAuthService creates a new dashboard authentication service

func (*DashboardAuthService) ChangePassword

func (s *DashboardAuthService) ChangePassword(ctx context.Context, userID uuid.UUID, currentPassword, newPassword string, ipAddress net.IP, userAgent string) error

ChangePassword changes a dashboard user's password

func (*DashboardAuthService) CreateUser

func (s *DashboardAuthService) CreateUser(ctx context.Context, email, password, fullName string) (*DashboardUser, error)

CreateUser creates a new dashboard user with email and password

func (*DashboardAuthService) DeleteAccount

func (s *DashboardAuthService) DeleteAccount(ctx context.Context, userID uuid.UUID, password string, ipAddress net.IP, userAgent string) error

DeleteAccount soft-deletes a dashboard user account

func (*DashboardAuthService) DisableTOTP

func (s *DashboardAuthService) DisableTOTP(ctx context.Context, userID uuid.UUID, password string, ipAddress net.IP, userAgent string) error

DisableTOTP disables 2FA for a user

func (*DashboardAuthService) EnableTOTP

func (s *DashboardAuthService) EnableTOTP(ctx context.Context, userID uuid.UUID, code string, ipAddress net.IP, userAgent string) ([]string, error)

EnableTOTP enables 2FA after verifying the TOTP code

func (*DashboardAuthService) FindOrCreateUserBySSO

func (s *DashboardAuthService) FindOrCreateUserBySSO(ctx context.Context, email, name, provider, providerUserID string) (*DashboardUser, bool, error)

FindOrCreateUserBySSO finds an existing user by SSO identity or email, or creates a new one Returns the user and a boolean indicating if a new user was created

func (*DashboardAuthService) GetDB

GetDB returns the database connection

func (*DashboardAuthService) GetUserByEmail

func (s *DashboardAuthService) GetUserByEmail(ctx context.Context, email string) (*DashboardUser, error)

GetUserByEmail finds a dashboard user by email

func (*DashboardAuthService) GetUserByID

func (s *DashboardAuthService) GetUserByID(ctx context.Context, userID uuid.UUID) (*DashboardUser, error)

GetUserByID fetches a dashboard user by ID

func (*DashboardAuthService) GetUserBySSOIdentity

func (s *DashboardAuthService) GetUserBySSOIdentity(ctx context.Context, provider, providerUserID string) (*DashboardUser, error)

GetUserBySSOIdentity finds a dashboard user by their SSO identity

func (*DashboardAuthService) HasExistingUsers

func (s *DashboardAuthService) HasExistingUsers(ctx context.Context) (bool, error)

HasExistingUsers checks if any dashboard users exist

func (*DashboardAuthService) LinkSSOIdentity

func (s *DashboardAuthService) LinkSSOIdentity(ctx context.Context, userID uuid.UUID, provider, providerUserID, email string) error

LinkSSOIdentity links an SSO identity to an existing dashboard user

func (*DashboardAuthService) Login

func (s *DashboardAuthService) Login(ctx context.Context, email, password string, ipAddress net.IP, userAgent string) (*DashboardUser, *LoginResponse, error)

Login authenticates a dashboard user with email and password

func (*DashboardAuthService) LoginViaSSO

func (s *DashboardAuthService) LoginViaSSO(ctx context.Context, user *DashboardUser, ipAddress net.IP, userAgent string) (*LoginResponse, error)

LoginViaSSO logs in a dashboard user via SSO and returns tokens

func (*DashboardAuthService) RefreshToken

func (s *DashboardAuthService) RefreshToken(ctx context.Context, refreshToken string) (*LoginResponse, error)

RefreshToken generates a new access token using a refresh token for dashboard users

func (*DashboardAuthService) RequestPasswordReset

func (s *DashboardAuthService) RequestPasswordReset(ctx context.Context, email string) (string, error)

RequestPasswordReset creates a password reset token for a dashboard user Returns the plaintext token (to be sent via email) or nil if user not found

func (*DashboardAuthService) ResetPassword

func (s *DashboardAuthService) ResetPassword(ctx context.Context, token, newPassword string) error

ResetPassword resets a dashboard user's password using a valid reset token

func (*DashboardAuthService) SetupTOTP

func (s *DashboardAuthService) SetupTOTP(ctx context.Context, userID uuid.UUID, email string, issuer string) (string, string, error)

SetupTOTP generates a new TOTP secret for 2FA If issuer is empty, uses the configured default

func (*DashboardAuthService) UpdateProfile

func (s *DashboardAuthService) UpdateProfile(ctx context.Context, userID uuid.UUID, fullName string, avatarURL *string) error

UpdateProfile updates a dashboard user's profile information

func (*DashboardAuthService) ValidateToken

func (s *DashboardAuthService) ValidateToken(token string) (*TokenClaims, error)

ValidateToken validates a JWT token and returns the claims

func (*DashboardAuthService) VerifyPasswordResetToken

func (s *DashboardAuthService) VerifyPasswordResetToken(ctx context.Context, token string) (bool, error)

VerifyPasswordResetToken verifies a password reset token is valid

func (*DashboardAuthService) VerifyTOTP

func (s *DashboardAuthService) VerifyTOTP(ctx context.Context, userID uuid.UUID, code string) error

VerifyTOTP verifies a TOTP code during login

type DashboardSession

type DashboardSession struct {
	ID             uuid.UUID `json:"id"`
	UserID         uuid.UUID `json:"user_id"`
	TokenHash      string    `json:"-"`
	IPAddress      *net.IP   `json:"ip_address,omitempty"`
	UserAgent      *string   `json:"user_agent,omitempty"`
	ExpiresAt      time.Time `json:"expires_at"`
	CreatedAt      time.Time `json:"created_at"`
	LastActivityAt time.Time `json:"last_activity_at"`
}

DashboardSession represents an active dashboard session

type DashboardUser

type DashboardUser struct {
	ID            uuid.UUID  `json:"id"`
	Email         string     `json:"email"`
	EmailVerified bool       `json:"email_verified"`
	FullName      *string    `json:"full_name,omitempty"`
	AvatarURL     *string    `json:"avatar_url,omitempty"`
	TOTPEnabled   bool       `json:"totp_enabled"`
	IsActive      bool       `json:"is_active"`
	IsLocked      bool       `json:"is_locked"`
	LockedUntil   *time.Time `json:"locked_until,omitempty"`
	LastLoginAt   *time.Time `json:"last_login_at,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
	Role          string     `json:"role,omitempty"` // Set from JWT claims, not stored in DB
}

DashboardUser represents a dashboard/platform administrator user

type DashboardUserValidator

type DashboardUserValidator struct{}

DashboardUserValidator validates dashboard user operations

func (*DashboardUserValidator) ValidateCreate

func (v *DashboardUserValidator) ValidateCreate(email, password, fullName string) error

ValidateCreate validates dashboard user creation

func (*DashboardUserValidator) ValidateUpdateProfile

func (v *DashboardUserValidator) ValidateUpdateProfile(fullName string, avatarURL *string) error

ValidateUpdateProfile validates profile update

type DefaultOTPSender

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

DefaultOTPSender implements OTPSender using email service

func NewDefaultOTPSender

func NewDefaultOTPSender(emailService EmailService, fromAddress, appName string) *DefaultOTPSender

NewDefaultOTPSender creates a new OTP sender

func (*DefaultOTPSender) SendEmailOTP

func (s *DefaultOTPSender) SendEmailOTP(ctx context.Context, to, code, purpose string) error

SendEmailOTP sends an OTP code via email

func (*DefaultOTPSender) SendSMSOTP

func (s *DefaultOTPSender) SendSMSOTP(ctx context.Context, to, code, purpose string) error

SendSMSOTP sends an OTP code via SMS

type EmailService

type EmailService interface {
	SendMagicLink(ctx context.Context, to, token, link string) error
	SendVerificationEmail(ctx context.Context, to, token, link string) error
	SendPasswordReset(ctx context.Context, to, token, link string) error
	SendInvitationEmail(ctx context.Context, to, inviterName, inviteLink string) error
	Send(ctx context.Context, to, subject, body string) error
	IsConfigured() bool
}

EmailService defines the unified interface for email operations. All email-related interfaces (FullEmailService, RealEmailService, EmailSender, PasswordResetEmailSender) have been consolidated into this single interface. The email.Manager / email.Service types satisfy this interface.

type EmailVerificationRepository

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

EmailVerificationRepository handles database operations for email verification tokens

func NewEmailVerificationRepository

func NewEmailVerificationRepository(db *database.Connection) *EmailVerificationRepository

NewEmailVerificationRepository creates a new email verification repository

func (*EmailVerificationRepository) Create

Create creates a new email verification token for a user SECURITY: The plaintext token is returned only once for sending via email. Only the hash is stored.

func (*EmailVerificationRepository) DeleteByUserID

func (r *EmailVerificationRepository) DeleteByUserID(ctx context.Context, userID string) error

DeleteByUserID deletes all email verification tokens for a user

func (*EmailVerificationRepository) DeleteExpired

func (r *EmailVerificationRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired deletes all expired email verification tokens

func (*EmailVerificationRepository) GetByToken

GetByToken retrieves an email verification token by its plaintext token SECURITY: The incoming plaintext token is hashed before lookup

func (*EmailVerificationRepository) MarkAsUsed

func (r *EmailVerificationRepository) MarkAsUsed(ctx context.Context, id string) error

MarkAsUsed marks an email verification token as used

func (*EmailVerificationRepository) Validate

Validate validates an email verification token

type EmailVerificationService

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

func NewEmailVerificationService

func NewEmailVerificationService(
	repo *EmailVerificationRepository,
	userRepo *UserRepository,
	settingsCache *SettingsCache,
	emailService EmailService,
	baseURL string,
	emailVerificationExpiry time.Duration,
) *EmailVerificationService

func (*EmailVerificationService) IsEmailVerificationRequired

func (s *EmailVerificationService) IsEmailVerificationRequired(ctx context.Context) bool

func (*EmailVerificationService) SendEmailVerification

func (s *EmailVerificationService) SendEmailVerification(ctx context.Context, userID, email string) error

func (*EmailVerificationService) VerifyEmailToken

func (s *EmailVerificationService) VerifyEmailToken(ctx context.Context, token string) (*User, error)

type EmailVerificationToken

type EmailVerificationToken struct {
	ID        string     `json:"id" db:"id"`
	UserID    string     `json:"user_id" db:"user_id"`
	TokenHash string     `json:"-" db:"token_hash"` // SECURITY: Only hash is stored, never exposed in JSON
	ExpiresAt time.Time  `json:"expires_at" db:"expires_at"`
	Used      bool       `json:"used" db:"used"`
	UsedAt    *time.Time `json:"used_at,omitempty" db:"used_at"`
	CreatedAt time.Time  `json:"created_at" db:"created_at"`
}

EmailVerificationToken represents an email verification token

type EmailVerificationTokenWithPlaintext

type EmailVerificationTokenWithPlaintext struct {
	EmailVerificationToken
	PlaintextToken string // The plaintext token to send to the user (not stored)
}

EmailVerificationTokenWithPlaintext is returned from Create with the plaintext token for sending via email. The plaintext token is never stored in the database.

type EnrichedUser

type EnrichedUser struct {
	ID                string                 `json:"id"`
	Email             string                 `json:"email"`
	EmailVerified     bool                   `json:"email_verified"`
	Role              string                 `json:"role"`
	Provider          string                 `json:"provider"` // "email", "invite_pending", "magic_link"
	ActiveSessions    int                    `json:"active_sessions"`
	LastSignIn        *time.Time             `json:"last_sign_in"`
	IsLocked          bool                   `json:"is_locked"`
	UserMetadata      map[string]interface{} `json:"user_metadata"`
	AppMetadata       map[string]interface{} `json:"app_metadata"`
	CreatedAt         time.Time              `json:"created_at"`
	UpdatedAt         time.Time              `json:"updated_at"`
	TenantAssignments []TenantAssignment     `json:"tenant_assignments,omitempty"`
}

EnrichedUser represents a user with additional metadata for admin view

type HCaptchaProvider

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

HCaptchaProvider implements CAPTCHA verification using hCaptcha

func NewHCaptchaProvider

func NewHCaptchaProvider(secretKey string, httpClient *http.Client) *HCaptchaProvider

NewHCaptchaProvider creates a new hCaptcha provider

func (*HCaptchaProvider) Name

func (p *HCaptchaProvider) Name() string

Name returns the provider name

func (*HCaptchaProvider) Verify

func (p *HCaptchaProvider) Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

Verify validates an hCaptcha response token

type IDTokenClaims

type IDTokenClaims struct {
	Subject       string // Provider's user ID (sub claim)
	Email         string
	EmailVerified bool
	Name          string
	Picture       string
	Nonce         string
}

IDTokenClaims contains the claims extracted from an OIDC ID token

type IdentityRepository

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

IdentityRepository handles database operations for user identities

func NewIdentityRepository

func NewIdentityRepository(db *database.Connection) *IdentityRepository

NewIdentityRepository creates a new identity repository

func (*IdentityRepository) Create

func (r *IdentityRepository) Create(ctx context.Context, userID, provider, providerUserID string, email *string, metadata map[string]interface{}) (*UserIdentity, error)

Create creates a new identity link

func (*IdentityRepository) Delete

func (r *IdentityRepository) Delete(ctx context.Context, id, userID string) error

Delete deletes an identity by ID

func (*IdentityRepository) DeleteByProvider

func (r *IdentityRepository) DeleteByProvider(ctx context.Context, userID, provider string) error

DeleteByProvider deletes all identities for a user and provider

func (*IdentityRepository) GetByID

func (r *IdentityRepository) GetByID(ctx context.Context, id string) (*UserIdentity, error)

GetByID retrieves an identity by ID

func (*IdentityRepository) GetByProviderAndUserID

func (r *IdentityRepository) GetByProviderAndUserID(ctx context.Context, provider, providerUserID string) (*UserIdentity, error)

GetByProviderAndUserID retrieves an identity by provider and provider user ID

func (*IdentityRepository) GetByUserID

func (r *IdentityRepository) GetByUserID(ctx context.Context, userID string) ([]UserIdentity, error)

GetByUserID retrieves all identities for a user

type IdentityService

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

IdentityService provides identity management functionality

func NewIdentityService

func NewIdentityService(
	repo *IdentityRepository,
	oauthManager *OAuthManager,
	stateStore StateStorer,
) *IdentityService

NewIdentityService creates a new identity service

func (*IdentityService) GetUserIdentities

func (s *IdentityService) GetUserIdentities(ctx context.Context, userID string) ([]UserIdentity, error)

GetUserIdentities retrieves all OAuth identities linked to a user

func (*IdentityService) LinkIdentity

func (s *IdentityService) LinkIdentity(ctx context.Context, userID, provider, providerUserID string, email *string, metadata map[string]interface{}) (*UserIdentity, error)

LinkIdentity creates or updates an identity link for a user (used for SAML/SSO)

func (*IdentityService) LinkIdentityCallback

func (s *IdentityService) LinkIdentityCallback(ctx context.Context, userID, provider, code, state string) (*UserIdentity, error)

LinkIdentityCallback handles the OAuth callback to complete identity linking

func (*IdentityService) LinkIdentityProvider

func (s *IdentityService) LinkIdentityProvider(ctx context.Context, userID string, provider string) (string, string, error)

LinkIdentityProvider initiates OAuth flow to link a new provider

func (*IdentityService) UnlinkIdentity

func (s *IdentityService) UnlinkIdentity(ctx context.Context, userID, identityID string) error

UnlinkIdentity removes an OAuth identity from a user

type ImpersonationRepository

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

func NewImpersonationRepository

func NewImpersonationRepository(db *database.Connection) *ImpersonationRepository

func (*ImpersonationRepository) Create

func (*ImpersonationRepository) EndSession

func (r *ImpersonationRepository) EndSession(ctx context.Context, sessionID string) error

func (*ImpersonationRepository) GetActiveByAdmin

func (r *ImpersonationRepository) GetActiveByAdmin(ctx context.Context, adminUserID string) (*ImpersonationSession, error)

func (*ImpersonationRepository) ListByAdmin

func (r *ImpersonationRepository) ListByAdmin(ctx context.Context, adminUserID string, limit, offset int) ([]*ImpersonationSession, error)

type ImpersonationService

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

func NewImpersonationService

func NewImpersonationService(
	repo *ImpersonationRepository,
	userRepo *UserRepository,
	jwtManager *JWTManager,
	db *database.Connection,
) *ImpersonationService

func (*ImpersonationService) GetActiveSession

func (s *ImpersonationService) GetActiveSession(ctx context.Context, adminUserID string) (*ImpersonationSession, error)

func (*ImpersonationService) ListSessions

func (s *ImpersonationService) ListSessions(ctx context.Context, adminUserID string, limit, offset int) ([]*ImpersonationSession, error)

func (*ImpersonationService) SetTokenBlacklistService

func (s *ImpersonationService) SetTokenBlacklistService(service *TokenBlacklistService)

func (*ImpersonationService) StartAnonImpersonation

func (s *ImpersonationService) StartAnonImpersonation(
	ctx context.Context,
	adminUserID string,
	tenantID string,
	reason string,
	ipAddress string,
	userAgent string,
) (*StartImpersonationResponse, error)

func (*ImpersonationService) StartImpersonation

func (s *ImpersonationService) StartImpersonation(
	ctx context.Context,
	adminUserID string,
	tenantID string,
	req StartImpersonationRequest,
) (*StartImpersonationResponse, error)

func (*ImpersonationService) StartServiceImpersonation

func (s *ImpersonationService) StartServiceImpersonation(
	ctx context.Context,
	adminUserID string,
	tenantID string,
	reason string,
	ipAddress string,
	userAgent string,
) (*StartImpersonationResponse, error)

func (*ImpersonationService) StopImpersonation

func (s *ImpersonationService) StopImpersonation(ctx context.Context, adminUserID string) error

type ImpersonationSession

type ImpersonationSession struct {
	ID                string            `json:"id" db:"id"`
	AdminUserID       string            `json:"admin_user_id" db:"admin_user_id"`
	TargetUserID      *string           `json:"target_user_id,omitempty" db:"target_user_id"`
	ImpersonationType ImpersonationType `json:"impersonation_type" db:"impersonation_type"`
	TargetRole        *string           `json:"target_role,omitempty" db:"target_role"`
	Reason            string            `json:"reason,omitempty" db:"reason"`
	StartedAt         time.Time         `json:"started_at" db:"started_at"`
	EndedAt           *time.Time        `json:"ended_at,omitempty" db:"ended_at"`
	IPAddress         string            `json:"ip_address,omitempty" db:"ip_address"`
	UserAgent         string            `json:"user_agent,omitempty" db:"user_agent"`
	IsActive          bool              `json:"is_active" db:"is_active"`
	AccessTokenJTI    string            `json:"access_token_jti,omitempty" db:"access_token_jti"`
	RefreshTokenJTI   string            `json:"refresh_token_jti,omitempty" db:"refresh_token_jti"`
	TenantID          *string           `json:"tenant_id,omitempty" db:"tenant_id"`
}

type ImpersonationType

type ImpersonationType string
const (
	ImpersonationTypeUser    ImpersonationType = "user"
	ImpersonationTypeAnon    ImpersonationType = "anon"
	ImpersonationTypeService ImpersonationType = "service"
)

type InstanceSetting

type InstanceSetting struct {
	ID          uuid.UUID              `json:"id"`
	Key         string                 `json:"key"`
	Value       map[string]interface{} `json:"value"`
	Description *string                `json:"description,omitempty"`
	IsPublic    bool                   `json:"is_public"`
	Category    string                 `json:"category"`
	CreatedAt   time.Time              `json:"created_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
}

InstanceSetting represents an instance-level (platform-wide) configuration setting

type InvitationService

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

InvitationService handles user invitation operations

func NewInvitationService

func NewInvitationService(db *database.Connection) *InvitationService

NewInvitationService creates a new invitation service

func (*InvitationService) AcceptInvitation

func (s *InvitationService) AcceptInvitation(ctx context.Context, token string) error

AcceptInvitation marks an invitation as accepted

func (*InvitationService) CleanupExpiredInvitations

func (s *InvitationService) CleanupExpiredInvitations(ctx context.Context) (int64, error)

CleanupExpiredInvitations removes expired invitation tokens

func (*InvitationService) CreateInvitation

func (s *InvitationService) CreateInvitation(ctx context.Context, email, role string, invitedBy *uuid.UUID, expiryDuration time.Duration) (*InvitationTokenWithPlaintext, error)

CreateInvitation creates a new invitation token

func (*InvitationService) CreateInvitationWithTenant

func (s *InvitationService) CreateInvitationWithTenant(ctx context.Context, email, role string, tenantID *uuid.UUID, invitedBy *uuid.UUID, expiryDuration time.Duration) (*InvitationTokenWithPlaintext, error)

CreateInvitationWithTenant creates a new invitation token with an optional tenant context

func (*InvitationService) GenerateToken

func (s *InvitationService) GenerateToken() (string, error)

GenerateToken generates a cryptographically secure random token

func (*InvitationService) GetInvitationByEmail

func (s *InvitationService) GetInvitationByEmail(ctx context.Context, email string) ([]InvitationToken, error)

GetInvitationByEmail retrieves pending invitations for an email

func (*InvitationService) ListInvitations

func (s *InvitationService) ListInvitations(ctx context.Context, includeAccepted, includeExpired bool) ([]InvitationToken, error)

ListInvitations retrieves all invitations (for admin panel)

func (*InvitationService) RevokeInvitation

func (s *InvitationService) RevokeInvitation(ctx context.Context, token string) error

RevokeInvitation revokes (deletes) an invitation token

func (*InvitationService) ValidateToken

func (s *InvitationService) ValidateToken(ctx context.Context, token string) (*InvitationToken, error)

ValidateToken validates an invitation token and returns the invitation

type InvitationToken

type InvitationToken struct {
	ID         uuid.UUID  `json:"id"`
	Email      string     `json:"email"`
	Token      string     `json:"-" db:"token"`
	TokenHash  *string    `json:"-" db:"token_hash"`
	Role       string     `json:"role"`
	TenantID   *uuid.UUID `json:"tenant_id,omitempty"`
	InvitedBy  *uuid.UUID `json:"invited_by,omitempty"`
	ExpiresAt  time.Time  `json:"expires_at"`
	Accepted   bool       `json:"accepted"`
	AcceptedAt *time.Time `json:"accepted_at,omitempty"`
	CreatedAt  time.Time  `json:"created_at"`
}

InvitationToken represents an invitation for a new user

type InvitationTokenWithPlaintext

type InvitationTokenWithPlaintext struct {
	*InvitationToken
	PlaintextToken string `json:"token"`
}

InvitationTokenWithPlaintext wraps InvitationToken with the plaintext token for one-time use (e.g., building invitation links). The plaintext is never exposed in JSON responses.

type InviteUserRequest

type InviteUserRequest struct {
	Email     string `json:"email"`
	Role      string `json:"role"`
	Password  string `json:"password,omitempty"`   // Optional: if provided, use this instead of generating
	SkipEmail bool   `json:"skip_email,omitempty"` // Optional: if true, don't send invitation email
	TenantID  string `json:"tenant_id,omitempty"`  // Optional: tenant to add the user to (for app users)
}

InviteUserRequest represents a request to invite a new user

type InviteUserResponse

type InviteUserResponse struct {
	User              *User  `json:"user"`
	TemporaryPassword string `json:"temporary_password,omitempty"` // Only if SMTP disabled
	EmailSent         bool   `json:"email_sent"`
	Message           string `json:"message"`
}

InviteUserResponse represents the response after inviting a user

type JWTManager

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

JWTManager handles JWT token operations

func NewJWTManager

func NewJWTManager(secretKey string, accessTTL, refreshTTL time.Duration) (*JWTManager, error)

NewJWTManager creates a new JWT manager

func NewJWTManagerWithConfig

func NewJWTManagerWithConfig(secretKey string, accessTTL, refreshTTL, serviceRoleTTL, anonTTL time.Duration) (*JWTManager, error)

NewJWTManagerWithConfig creates a new JWT manager with full configuration

func (*JWTManager) ExtractUserID

func (m *JWTManager) ExtractUserID(tokenString string) (string, error)

ExtractUserID extracts the user ID from a token

func (*JWTManager) GenerateAccessToken

func (m *JWTManager) GenerateAccessToken(userID, email, role string, userMetadata, appMetadata any, opts ...TokenOption) (string, *TokenClaims, error)

GenerateAccessToken generates a new access token

func (*JWTManager) GenerateAccessTokenWithTenant

func (m *JWTManager) GenerateAccessTokenWithTenant(userID, email, role string, userMetadata, appMetadata any, tenantOpts TenantTokenOptions) (string, *TokenClaims, error)

GenerateAccessTokenWithTenant generates a new access token with tenant context

func (*JWTManager) GenerateAnonToken

func (m *JWTManager) GenerateAnonToken() (string, error)

GenerateAnonToken generates a JWT with anon role for anonymous access

func (*JWTManager) GenerateAnonTokenWithTenant

func (m *JWTManager) GenerateAnonTokenWithTenant(tenantID *string) (string, error)

GenerateAnonTokenWithTenant generates a JWT with anon role and tenant context

func (*JWTManager) GenerateAnonymousAccessToken

func (m *JWTManager) GenerateAnonymousAccessToken(userID string) (string, error)

GenerateAnonymousAccessToken generates an access token for an anonymous user

func (*JWTManager) GenerateAnonymousRefreshToken

func (m *JWTManager) GenerateAnonymousRefreshToken(userID string) (string, error)

GenerateAnonymousRefreshToken generates a refresh token for an anonymous user

func (*JWTManager) GenerateRefreshToken

func (m *JWTManager) GenerateRefreshToken(userID, email, role, sessionID string, userMetadata, appMetadata any, opts ...TokenOption) (string, *TokenClaims, error)

GenerateRefreshToken generates a new refresh token

func (*JWTManager) GenerateServiceRoleToken

func (m *JWTManager) GenerateServiceRoleToken() (string, error)

GenerateServiceRoleToken generates a JWT with service_role that bypasses RLS

func (*JWTManager) GenerateServiceRoleTokenWithTenant

func (m *JWTManager) GenerateServiceRoleTokenWithTenant(tenantID *string) (string, error)

GenerateServiceRoleTokenWithTenant generates a JWT with service_role and tenant context

func (*JWTManager) GenerateTokenPair

func (m *JWTManager) GenerateTokenPair(userID, email, role string, userMetadata, appMetadata any) (accessToken, refreshToken string, sessionID string, err error)

GenerateTokenPair generates both access and refresh tokens

func (*JWTManager) GenerateTokenPairWithTenant

func (m *JWTManager) GenerateTokenPairWithTenant(userID, email, role string, userMetadata, appMetadata any, tenantOpts TenantTokenOptions) (accessToken, refreshToken string, sessionID string, err error)

GenerateTokenPairWithTenant generates both access and refresh tokens with tenant context

func (*JWTManager) GetMaxTokenTTL

func (m *JWTManager) GetMaxTokenTTL() time.Duration

GetMaxTokenTTL returns the maximum TTL among all token types This is used to determine how long a user-wide revocation marker should persist

func (*JWTManager) GetTokenExpiry

func (m *JWTManager) GetTokenExpiry(tokenString string) (time.Time, error)

GetTokenExpiry returns when a token expires

func (*JWTManager) RefreshAccessToken

func (m *JWTManager) RefreshAccessToken(refreshTokenString string) (string, error)

RefreshAccessToken generates a new access token from a refresh token

func (*JWTManager) RefreshAccessTokenWithTenant

func (m *JWTManager) RefreshAccessTokenWithTenant(refreshTokenString string, tenantOpts *TenantTokenOptions) (string, error)

RefreshAccessTokenWithTenant generates a new access token from a refresh token, preserving tenant context

func (*JWTManager) ValidateAccessToken

func (m *JWTManager) ValidateAccessToken(tokenString string) (*TokenClaims, error)

ValidateAccessToken validates an access token specifically

func (*JWTManager) ValidateRefreshToken

func (m *JWTManager) ValidateRefreshToken(tokenString string) (*TokenClaims, error)

ValidateRefreshToken validates a refresh token specifically

func (*JWTManager) ValidateServiceRoleToken

func (m *JWTManager) ValidateServiceRoleToken(tokenString string) (*TokenClaims, error)

ValidateServiceRoleToken validates a JWT that contains a role claim (anon, service_role, authenticated) Unlike user tokens, these don't require user lookup or revocation checks.

func (*JWTManager) ValidateToken

func (m *JWTManager) ValidateToken(tokenString string) (*TokenClaims, error)

ValidateToken validates and parses a JWT token

func (*JWTManager) ValidateTokenWithSecret

func (m *JWTManager) ValidateTokenWithSecret(tokenString, secretKey string) (*TokenClaims, error)

ValidateTokenWithSecret validates and parses a JWT token using a specific secret key This is used for multi-tenant scenarios where each tenant may have a different JWT secret

type LoginResponse

type LoginResponse struct {
	AccessToken  string
	RefreshToken string
	ExpiresIn    int64
}

LoginResponse contains the tokens returned from login

type LogoutRequestResult

type LogoutRequestResult struct {
	RedirectURL string // URL to redirect user to IdP for logout
	RequestID   string // ID of the LogoutRequest (for matching response)
	Binding     string // "redirect" or "post"
}

LogoutRequestResult contains the result of generating a SAML LogoutRequest

type MFAService

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

func NewMFAService

func NewMFAService(
	userRepo *UserRepository,
	sessionRepo *SessionRepository,
	jwtManager *JWTManager,
	passwordHasher *PasswordHasher,
	db *database.Connection,
	cfg *config.AuthConfig,
) *MFAService

func (*MFAService) DisableTOTP

func (m *MFAService) DisableTOTP(ctx context.Context, userID, password string) error

func (*MFAService) EnableTOTP

func (m *MFAService) EnableTOTP(ctx context.Context, userID, code string) ([]string, error)

func (*MFAService) GenerateTokensForUser

func (m *MFAService) GenerateTokensForUser(ctx context.Context, userID string) (*SignInResponse, error)

func (*MFAService) IsTOTPEnabled

func (m *MFAService) IsTOTPEnabled(ctx context.Context, userID string) (bool, error)

func (*MFAService) SetEncryptionKey

func (m *MFAService) SetEncryptionKey(key string)

func (*MFAService) SetTOTPRateLimiter

func (m *MFAService) SetTOTPRateLimiter(limiter *TOTPRateLimiter)

func (*MFAService) SetupTOTP

func (m *MFAService) SetupTOTP(ctx context.Context, userID string, issuer string) (*TOTPSetupResponse, error)

func (*MFAService) VerifyTOTP

func (m *MFAService) VerifyTOTP(ctx context.Context, userID, code string) error

func (*MFAService) VerifyTOTPWithContext

func (m *MFAService) VerifyTOTPWithContext(ctx context.Context, userID, code, ipAddress, userAgent string) error
type MagicLink struct {
	ID        string     `json:"id" db:"id"`
	Email     string     `json:"email" db:"email"`
	TokenHash string     `json:"-" db:"token_hash"` // SECURITY: Only hash is stored, never exposed in JSON
	ExpiresAt time.Time  `json:"expires_at" db:"expires_at"`
	UsedAt    *time.Time `json:"used_at,omitempty" db:"used_at"`
	CreatedAt time.Time  `json:"created_at" db:"created_at"`
}

MagicLink represents a passwordless authentication link

type MagicLinkRepository

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

MagicLinkRepository handles database operations for magic links

func NewMagicLinkRepository

func NewMagicLinkRepository(db *database.Connection) *MagicLinkRepository

NewMagicLinkRepository creates a new magic link repository

func (*MagicLinkRepository) Create

func (r *MagicLinkRepository) Create(ctx context.Context, email string, expiryDuration time.Duration) (*MagicLinkWithToken, error)

Create creates a new magic link SECURITY: The plaintext token is returned only once for sending via email. Only the hash is stored.

func (*MagicLinkRepository) DeleteByEmail

func (r *MagicLinkRepository) DeleteByEmail(ctx context.Context, email string) error

DeleteByEmail deletes all magic links for an email

func (*MagicLinkRepository) DeleteExpired

func (r *MagicLinkRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired deletes all expired magic links

func (*MagicLinkRepository) GetByToken

func (r *MagicLinkRepository) GetByToken(ctx context.Context, token string) (*MagicLink, error)

GetByToken retrieves a magic link by token SECURITY: The incoming plaintext token is hashed before lookup

func (*MagicLinkRepository) MarkAsUsed

func (r *MagicLinkRepository) MarkAsUsed(ctx context.Context, id string) error

MarkAsUsed marks a magic link as used

func (*MagicLinkRepository) Validate

func (r *MagicLinkRepository) Validate(ctx context.Context, token string) (*MagicLink, error)

Validate validates a magic link token

type MagicLinkRepositoryInterface

type MagicLinkRepositoryInterface interface {
	// Create generates a new magic link for an email
	// Returns MagicLinkWithToken containing the plaintext token (for sending via email)
	// SECURITY: Only the hash is stored in the database
	Create(ctx context.Context, email string, expiryDuration time.Duration) (*MagicLinkWithToken, error)

	// GetByToken retrieves a magic link by its token
	// SECURITY: The incoming token is hashed before lookup
	GetByToken(ctx context.Context, token string) (*MagicLink, error)

	// Validate checks if a magic link token is valid and not expired
	Validate(ctx context.Context, token string) (*MagicLink, error)

	// MarkAsUsed marks a magic link as used
	MarkAsUsed(ctx context.Context, id string) error

	// DeleteExpired removes expired magic links (cleanup job)
	DeleteExpired(ctx context.Context) (int64, error)

	// DeleteByEmail removes all magic links for an email
	DeleteByEmail(ctx context.Context, email string) error
}

MagicLinkRepositoryInterface defines magic link (passwordless) operations.

type MagicLinkService

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

MagicLinkService provides magic link functionality

func NewMagicLinkService

func NewMagicLinkService(
	repo *MagicLinkRepository,
	userRepo *UserRepository,
	emailSender EmailService,
	linkDuration time.Duration,
	baseURL string,
) *MagicLinkService

NewMagicLinkService creates a new magic link service

func (s *MagicLinkService) SendMagicLink(ctx context.Context, email string) error

SendMagicLink sends a magic link to the specified email

func (s *MagicLinkService) VerifyMagicLink(ctx context.Context, token string) (string, error)

VerifyMagicLink verifies a magic link and returns the email

type MagicLinkWithToken

type MagicLinkWithToken struct {
	MagicLink
	PlaintextToken string // The plaintext token to send to the user (not stored)
}

MagicLinkWithToken is returned from Create with the plaintext token for sending via email. The plaintext token is never stored in the database.

type MockCaptchaProvider

type MockCaptchaProvider struct {
	VerifyFunc func(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)
	NameValue  string
}

MockCaptchaProvider is a mock implementation of CaptchaProvider for testing

func (*MockCaptchaProvider) Name

func (m *MockCaptchaProvider) Name() string

Name implements CaptchaProvider

func (*MockCaptchaProvider) Verify

func (m *MockCaptchaProvider) Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

Verify implements CaptchaProvider

type MockOAuthManager

type MockOAuthManager struct {
	AuthURLFn      func(provider, state string) (string, error)
	ExchangeCodeFn func(ctx context.Context, provider, code string) (string, map[string]interface{}, error)
	GetUserInfoFn  func(ctx context.Context, provider string, tokenStr string) (map[string]interface{}, error)
	// contains filtered or unexported fields
}

MockOAuthManager is a mock OAuth manager for testing

func NewMockOAuthManager

func NewMockOAuthManager() *MockOAuthManager

NewMockOAuthManager creates a new mock OAuth manager

func (*MockOAuthManager) ExchangeCode

func (m *MockOAuthManager) ExchangeCode(ctx context.Context, provider, code string) (string, map[string]interface{}, error)

ExchangeCode exchanges an authorization code for tokens

func (*MockOAuthManager) GetAuthURL

func (m *MockOAuthManager) GetAuthURL(provider, state string) (string, error)

GetAuthURL generates an OAuth authorization URL

func (*MockOAuthManager) GetUserInfo

func (m *MockOAuthManager) GetUserInfo(ctx context.Context, provider string, tokenStr string) (map[string]interface{}, error)

GetUserInfo retrieves user information from the OAuth provider

func (*MockOAuthManager) RegisterProvider

func (m *MockOAuthManager) RegisterProvider(provider string)

RegisterProvider registers an OAuth provider

type MockPasswordResetRepository

type MockPasswordResetRepository struct {
	ValidateFn       func(ctx context.Context, token string) (*PasswordResetToken, error)
	CreateFn         func(ctx context.Context, userID string, expiryDuration time.Duration) (*PasswordResetTokenWithPlaintext, error)
	MarkAsUsedFn     func(ctx context.Context, id string) error
	GetLatestFn      func(ctx context.Context, userID string) (*PasswordResetToken, error)
	DeleteByUserIDFn func(ctx context.Context, userID string) error
	// contains filtered or unexported fields
}

MockPasswordResetRepository is an in-memory implementation of password reset repository for testing

func NewMockPasswordResetRepository

func NewMockPasswordResetRepository() *MockPasswordResetRepository

NewMockPasswordResetRepository creates a new mock password reset repository

func (*MockPasswordResetRepository) Create

func (*MockPasswordResetRepository) DeleteByUserID

func (m *MockPasswordResetRepository) DeleteByUserID(ctx context.Context, userID string) error

func (*MockPasswordResetRepository) DeleteExpired

func (m *MockPasswordResetRepository) DeleteExpired(ctx context.Context) (int64, error)

func (*MockPasswordResetRepository) GetByToken

func (*MockPasswordResetRepository) GetLatestByUserID

func (m *MockPasswordResetRepository) GetLatestByUserID(ctx context.Context, userID string) (*PasswordResetToken, error)

func (*MockPasswordResetRepository) MarkAsUsed

func (m *MockPasswordResetRepository) MarkAsUsed(ctx context.Context, id string) error

func (*MockPasswordResetRepository) Validate

type MockSessionRepository

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

MockSessionRepository is an in-memory implementation of SessionRepositoryInterface for testing.

func NewMockSessionRepository

func NewMockSessionRepository() *MockSessionRepository

NewMockSessionRepository creates a new mock session repository.

func (*MockSessionRepository) Count

func (m *MockSessionRepository) Count(ctx context.Context) (int, error)

func (*MockSessionRepository) CountByUserID

func (m *MockSessionRepository) CountByUserID(ctx context.Context, userID string) (int, error)

CountByUserID returns the number of active sessions for a user

func (*MockSessionRepository) Create

func (m *MockSessionRepository) Create(ctx context.Context, userID, accessToken, refreshToken string, expiresAt time.Time) (*Session, error)

func (*MockSessionRepository) Delete

func (m *MockSessionRepository) Delete(ctx context.Context, id string) error

func (*MockSessionRepository) DeleteByAccessToken

func (m *MockSessionRepository) DeleteByAccessToken(ctx context.Context, accessToken string) error

func (*MockSessionRepository) DeleteByUserID

func (m *MockSessionRepository) DeleteByUserID(ctx context.Context, userID string) error

func (*MockSessionRepository) DeleteExpired

func (m *MockSessionRepository) DeleteExpired(ctx context.Context) (int64, error)

func (*MockSessionRepository) GetByAccessToken

func (m *MockSessionRepository) GetByAccessToken(ctx context.Context, accessToken string) (*Session, error)

func (*MockSessionRepository) GetByRefreshToken

func (m *MockSessionRepository) GetByRefreshToken(ctx context.Context, refreshToken string) (*Session, error)

func (*MockSessionRepository) GetByUserID

func (m *MockSessionRepository) GetByUserID(ctx context.Context, userID string) ([]*Session, error)

func (*MockSessionRepository) ListAll

func (m *MockSessionRepository) ListAll(ctx context.Context, includeExpired bool) ([]SessionWithUser, error)

ListAll returns all sessions with user info for admin views

func (*MockSessionRepository) ListAllPaginated

func (m *MockSessionRepository) ListAllPaginated(ctx context.Context, includeExpired bool, limit, offset int) ([]SessionWithUser, int, error)

ListAllPaginated returns paginated sessions with user info

func (*MockSessionRepository) UpdateAccessToken

func (m *MockSessionRepository) UpdateAccessToken(ctx context.Context, id, accessToken string) error

UpdateAccessToken updates only the access token for a session

func (*MockSessionRepository) UpdateTokens

func (m *MockSessionRepository) UpdateTokens(ctx context.Context, id, accessToken, refreshToken string, expiresAt time.Time) error

type MockTOTPRateLimiter

type MockTOTPRateLimiter struct {
	CheckLimitFn    func(ctx context.Context, userID string) error
	RecordAttemptFn func(ctx context.Context, userID string, success bool, ipAddress, userAgent string) error
	// contains filtered or unexported fields
}

MockTOTPRateLimiter is a mock TOTP rate limiter for testing

func NewMockTOTPRateLimiter

func NewMockTOTPRateLimiter() *MockTOTPRateLimiter

NewMockTOTPRateLimiter creates a new mock TOTP rate limiter

func (*MockTOTPRateLimiter) CheckRateLimit

func (m *MockTOTPRateLimiter) CheckRateLimit(ctx context.Context, userID string) error

CheckRateLimit checks if the user has exceeded the TOTP attempt limit

func (*MockTOTPRateLimiter) GetFailedAttempts

func (m *MockTOTPRateLimiter) GetFailedAttempts(userID string) int

GetFailedAttempts returns the current failed attempt count for a user

func (*MockTOTPRateLimiter) RecordAttempt

func (m *MockTOTPRateLimiter) RecordAttempt(ctx context.Context, userID string, success bool, ipAddress, userAgent string) error

RecordAttempt records a TOTP verification attempt (success or failure)

func (*MockTOTPRateLimiter) Reset

func (m *MockTOTPRateLimiter) Reset(userID string)

Reset clears all rate limiting state for a user

func (*MockTOTPRateLimiter) SetBlockedUntil

func (m *MockTOTPRateLimiter) SetBlockedUntil(userID string, until time.Time)

SetBlockedUntil marks a user as blocked until a specific time

func (*MockTOTPRateLimiter) SetMaxAttempts

func (m *MockTOTPRateLimiter) SetMaxAttempts(max int)

SetMaxAttempts sets the maximum attempts before rate limiting kicks in

type MockTokenBlacklistRepository

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

MockTokenBlacklistRepository is an in-memory implementation of TokenBlacklistRepositoryInterface for testing.

func NewMockTokenBlacklistRepository

func NewMockTokenBlacklistRepository() *MockTokenBlacklistRepository

NewMockTokenBlacklistRepository creates a new mock token blacklist repository.

func (*MockTokenBlacklistRepository) Add

func (m *MockTokenBlacklistRepository) Add(ctx context.Context, jti string, revokedBy *string, reason string, expiresAt time.Time) error

func (*MockTokenBlacklistRepository) DeleteByUser

func (m *MockTokenBlacklistRepository) DeleteByUser(ctx context.Context, userID string) error

func (*MockTokenBlacklistRepository) DeleteExpired

func (m *MockTokenBlacklistRepository) DeleteExpired(ctx context.Context) (int64, error)

func (*MockTokenBlacklistRepository) GetByJTI

func (*MockTokenBlacklistRepository) IsBlacklisted

func (m *MockTokenBlacklistRepository) IsBlacklisted(ctx context.Context, jti string) (bool, error)

func (*MockTokenBlacklistRepository) RevokeAllUserTokens

func (m *MockTokenBlacklistRepository) RevokeAllUserTokens(ctx context.Context, userID, reason string, expiry time.Duration) error

type MockUserRepository

type MockUserRepository struct {
	CreateFn func(ctx context.Context, req CreateUserRequest, passwordHash string) (*User, error) // Optional override
	// contains filtered or unexported fields
}

MockUserRepository is an in-memory implementation of UserRepositoryInterface for testing.

func NewMockUserRepository

func NewMockUserRepository() *MockUserRepository

NewMockUserRepository creates a new mock user repository.

func (*MockUserRepository) Count

func (m *MockUserRepository) Count(ctx context.Context) (int, error)

func (*MockUserRepository) Create

func (m *MockUserRepository) Create(ctx context.Context, req CreateUserRequest, passwordHash string) (*User, error)

func (*MockUserRepository) Delete

func (m *MockUserRepository) Delete(ctx context.Context, id string) error

func (*MockUserRepository) GetByEmail

func (m *MockUserRepository) GetByEmail(ctx context.Context, email string) (*User, error)

func (*MockUserRepository) GetByID

func (m *MockUserRepository) GetByID(ctx context.Context, id string) (*User, error)

func (*MockUserRepository) IncrementFailedLoginAttempts

func (m *MockUserRepository) IncrementFailedLoginAttempts(ctx context.Context, userID string) error

func (*MockUserRepository) List

func (m *MockUserRepository) List(ctx context.Context, limit, offset int) ([]*User, error)

func (*MockUserRepository) LockUser

func (m *MockUserRepository) LockUser(ctx context.Context, userID string, lockDuration time.Duration) error

LockUser locks a user account for a specified duration

func (*MockUserRepository) ResetFailedLoginAttempts

func (m *MockUserRepository) ResetFailedLoginAttempts(ctx context.Context, userID string) error

func (*MockUserRepository) UnlockUser

func (m *MockUserRepository) UnlockUser(ctx context.Context, userID string) error

func (*MockUserRepository) Update

func (m *MockUserRepository) Update(ctx context.Context, id string, req UpdateUserRequest) (*User, error)

func (*MockUserRepository) UpdateEmail

func (m *MockUserRepository) UpdateEmail(ctx context.Context, id, newEmail string) error

UpdateEmail updates a user's email

func (*MockUserRepository) UpdatePassword

func (m *MockUserRepository) UpdatePassword(ctx context.Context, id string, newPasswordHash string) error

func (*MockUserRepository) UpdateRole

func (m *MockUserRepository) UpdateRole(ctx context.Context, userID, role string) error

UpdateRole updates a user's role

func (*MockUserRepository) VerifyEmail

func (m *MockUserRepository) VerifyEmail(ctx context.Context, id string) error

type NoOpOTPSender

type NoOpOTPSender struct{}

NoOpOTPSender is a no-op OTP sender for testing

func (*NoOpOTPSender) SendEmailOTP

func (s *NoOpOTPSender) SendEmailOTP(ctx context.Context, to, code, purpose string) error

SendEmailOTP does nothing

func (*NoOpOTPSender) SendSMSOTP

func (s *NoOpOTPSender) SendSMSOTP(ctx context.Context, to, code, purpose string) error

SendSMSOTP does nothing

type NonceRepository

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

NonceRepository handles database operations for reauthentication nonces. This enables stateless multi-instance deployments without sticky sessions.

func NewNonceRepository

func NewNonceRepository(db *database.Connection) *NonceRepository

NewNonceRepository creates a new nonce repository

func (*NonceRepository) Cleanup

func (r *NonceRepository) Cleanup(ctx context.Context) (int64, error)

Cleanup removes expired nonces from the database

func (*NonceRepository) Set

func (r *NonceRepository) Set(ctx context.Context, nonce, userID string, ttl time.Duration) error

Set stores a nonce with its associated user ID and TTL

func (*NonceRepository) Validate

func (r *NonceRepository) Validate(ctx context.Context, nonce, userID string) (bool, error)

Validate checks if a nonce is valid for the given user and removes it (single-use). Returns true if the nonce exists, belongs to the user, and hasn't expired. Uses atomic DELETE with RETURNING to ensure single-use semantics across instances.

type NonceService

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

func NewNonceService

func NewNonceService(nonceRepo *NonceRepository, userRepo *UserRepository) *NonceService

func (*NonceService) CleanupExpiredNonces

func (n *NonceService) CleanupExpiredNonces(ctx context.Context) (int64, error)

func (*NonceService) Reauthenticate

func (n *NonceService) Reauthenticate(ctx context.Context, userID string) (string, error)

func (*NonceService) VerifyNonce

func (n *NonceService) VerifyNonce(ctx context.Context, nonce, userID string) bool

type NonceStore

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

NonceStore manages reauthentication nonces for sensitive operations. Uses a mutex to protect concurrent access from multiple goroutines. Nonces are single-use and expire after a configured TTL.

func NewNonceStore

func NewNonceStore() *NonceStore

NewNonceStore creates a new nonce store

func (*NonceStore) Cleanup

func (s *NonceStore) Cleanup()

Cleanup removes expired nonces

func (*NonceStore) Set

func (s *NonceStore) Set(nonce, userID string, ttl time.Duration)

Set stores a nonce with its associated user ID and TTL

func (*NonceStore) StartCleanup

func (s *NonceStore) StartCleanup(interval time.Duration) chan struct{}

StartCleanup starts a background goroutine that periodically cleans up expired nonces. Returns a stop channel that can be closed to stop the cleanup goroutine.

func (*NonceStore) Validate

func (s *NonceStore) Validate(nonce, userID string) bool

Validate checks if a nonce is valid for the given user and removes it (single-use). Returns true if the nonce exists, belongs to the user, and hasn't expired.

type OAuthConfig

type OAuthConfig struct {
	ClientID     string
	ClientSecret string
	RedirectURL  string
	Scopes       []string
}

OAuthConfig holds OAuth provider configuration

type OAuthLogoutResult

type OAuthLogoutResult struct {
	// LocalLogoutComplete indicates JWT tokens were revoked
	LocalLogoutComplete bool `json:"local_tokens_revoked"`
	// ProviderTokenRevoked indicates the token was revoked at the provider
	ProviderTokenRevoked bool `json:"provider_token_revoked"`
	// RequiresRedirect indicates the user should be redirected for OIDC logout
	RequiresRedirect bool `json:"requires_redirect,omitempty"`
	// RedirectURL is the URL to redirect to for OIDC logout
	RedirectURL string `json:"redirect_url,omitempty"`
	// Provider is the name of the OAuth provider
	Provider string `json:"provider"`
	// Warning contains any warning message
	Warning string `json:"warning,omitempty"`
}

OAuthLogoutResult contains the result of an OAuth logout operation

type OAuthLogoutService

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

OAuthLogoutService handles OAuth Single Logout operations

func NewOAuthLogoutService

func NewOAuthLogoutService(db *database.Connection, encryptionKey string) *OAuthLogoutService

NewOAuthLogoutService creates a new OAuth logout service

func (*OAuthLogoutService) CleanupExpiredLogoutStates

func (s *OAuthLogoutService) CleanupExpiredLogoutStates(ctx context.Context) error

CleanupExpiredLogoutStates removes expired logout states

func (*OAuthLogoutService) DeleteUserOAuthToken

func (s *OAuthLogoutService) DeleteUserOAuthToken(ctx context.Context, userID, provider string) error

DeleteUserOAuthToken removes the user's OAuth token after logout

func (*OAuthLogoutService) GenerateOIDCLogoutURL

func (s *OAuthLogoutService) GenerateOIDCLogoutURL(endSessionEndpoint, idToken, postLogoutRedirectURI, state string) (string, error)

GenerateOIDCLogoutURL generates the OIDC RP-Initiated Logout URL

func (*OAuthLogoutService) GetUserOAuthToken

func (s *OAuthLogoutService) GetUserOAuthToken(ctx context.Context, userID, provider string) (*StoredOAuthToken, error)

GetUserOAuthToken retrieves the user's stored OAuth token for a provider

func (*OAuthLogoutService) RevokeTokenAtProvider

func (s *OAuthLogoutService) RevokeTokenAtProvider(ctx context.Context, revocationEndpoint, token, tokenTypeHint, clientID, clientSecret string) error

RevokeTokenAtProvider revokes the OAuth token at the provider using RFC 7009

func (*OAuthLogoutService) StoreLogoutState

func (s *OAuthLogoutService) StoreLogoutState(ctx context.Context, userID, provider, state, postLogoutRedirectURI string) error

StoreLogoutState stores a logout state for CSRF protection

func (*OAuthLogoutService) ValidateLogoutState

func (s *OAuthLogoutService) ValidateLogoutState(ctx context.Context, state string) (*OAuthLogoutState, error)

ValidateLogoutState validates and consumes a logout state

type OAuthLogoutState

type OAuthLogoutState struct {
	ID                    string
	UserID                string
	Provider              string
	State                 string
	PostLogoutRedirectURI string
	CreatedAt             time.Time
	ExpiresAt             time.Time
}

OAuthLogoutState represents a stored logout state for CSRF protection

type OAuthManager

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

OAuthManager handles OAuth authentication flows

func NewOAuthManager

func NewOAuthManager() *OAuthManager

NewOAuthManager creates a new OAuth manager

func (*OAuthManager) ExchangeCode

func (m *OAuthManager) ExchangeCode(ctx context.Context, provider OAuthProvider, code string) (*oauth2.Token, error)

ExchangeCode exchanges an authorization code for tokens

func (*OAuthManager) GetAuthURL

func (m *OAuthManager) GetAuthURL(provider OAuthProvider, state string) (string, error)

GetAuthURL returns the OAuth authorization URL

func (*OAuthManager) GetEndpoint

func (m *OAuthManager) GetEndpoint(provider OAuthProvider) oauth2.Endpoint

GetEndpoint returns the OAuth2 endpoint for a provider

func (*OAuthManager) GetUserInfo

func (m *OAuthManager) GetUserInfo(ctx context.Context, provider OAuthProvider, token *oauth2.Token) (map[string]interface{}, error)

GetUserInfo retrieves user information from the OAuth provider

func (*OAuthManager) GetUserInfoURL

func (m *OAuthManager) GetUserInfoURL(provider OAuthProvider) string

GetUserInfoURL returns the user info endpoint for a provider

func (*OAuthManager) RegisterProvider

func (m *OAuthManager) RegisterProvider(provider OAuthProvider, config OAuthConfig) error

RegisterProvider registers an OAuth provider

type OAuthProvider

type OAuthProvider string

OAuthProvider represents different OAuth providers

const (
	// ProviderGoogle represents Google OAuth
	ProviderGoogle OAuthProvider = "google"
	// ProviderGithub represents GitHub OAuth
	ProviderGithub OAuthProvider = "github"
	// ProviderMicrosoft represents Microsoft OAuth
	ProviderMicrosoft OAuthProvider = "microsoft"
	// ProviderApple represents Apple OAuth
	ProviderApple OAuthProvider = "apple"
	// ProviderFacebook represents Facebook OAuth
	ProviderFacebook OAuthProvider = "facebook"
	// ProviderTwitter represents Twitter OAuth
	ProviderTwitter OAuthProvider = "twitter"
	// ProviderLinkedIn represents LinkedIn OAuth
	ProviderLinkedIn OAuthProvider = "linkedin"
	// ProviderGitLab represents GitLab OAuth
	ProviderGitLab OAuthProvider = "gitlab"
	// ProviderBitbucket represents Bitbucket OAuth
	ProviderBitbucket OAuthProvider = "bitbucket"
)

type OAuthProviderRBAC

type OAuthProviderRBAC struct {
	Name           string
	RequiredClaims map[string][]string
	DeniedClaims   map[string][]string
}

OAuthProviderRBAC represents OAuth provider configuration with RBAC fields

type OIDCVerifier

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

OIDCVerifier handles OIDC ID token verification for multiple providers

func NewOIDCVerifier

func NewOIDCVerifier(ctx context.Context, cfg *config.AuthConfig) (*OIDCVerifier, error)

NewOIDCVerifier creates a new OIDC verifier with the configured providers

func (*OIDCVerifier) IsProviderConfigured

func (v *OIDCVerifier) IsProviderConfigured(providerName string) bool

IsProviderConfigured checks if a provider is configured

func (*OIDCVerifier) ListProviders

func (v *OIDCVerifier) ListProviders() []string

ListProviders returns a list of configured provider names

func (*OIDCVerifier) Verify

func (v *OIDCVerifier) Verify(ctx context.Context, providerName, idToken, expectedNonce string) (*IDTokenClaims, error)

Verify verifies an ID token from the specified provider and returns the claims

type OTPCode

type OTPCode struct {
	ID          string     `json:"id" db:"id"`
	Email       *string    `json:"email,omitempty" db:"email"`
	Phone       *string    `json:"phone,omitempty" db:"phone"`
	CodeHash    *string    `json:"-" db:"code_hash"`
	Type        string     `json:"type" db:"type"`
	Purpose     string     `json:"purpose" db:"purpose"`
	ExpiresAt   time.Time  `json:"expires_at" db:"expires_at"`
	Used        bool       `json:"used" db:"used"`
	UsedAt      *time.Time `json:"used_at,omitempty" db:"used_at"`
	Attempts    int        `json:"attempts" db:"attempts"`
	MaxAttempts int        `json:"max_attempts" db:"max_attempts"`
	IPAddress   *string    `json:"ip_address,omitempty" db:"ip_address"`
	UserAgent   *string    `json:"user_agent,omitempty" db:"user_agent"`
	CreatedAt   time.Time  `json:"created_at" db:"created_at"`
}

OTPCode represents a one-time password code

type OTPCodeWithPlaintext

type OTPCodeWithPlaintext struct {
	*OTPCode
	PlaintextCode string `json:"-"`
}

OTPCodeWithPlaintext wraps OTPCode with the plaintext code for one-time use (e.g., sending via email/SMS). The plaintext code is never persisted.

type OTPRepository

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

OTPRepository handles database operations for OTP codes

func NewOTPRepository

func NewOTPRepository(db *database.Connection) *OTPRepository

NewOTPRepository creates a new OTP repository

func (*OTPRepository) Create

func (r *OTPRepository) Create(ctx context.Context, email *string, phone *string, otpType, purpose string, expiryDuration time.Duration) (*OTPCodeWithPlaintext, error)

Create creates a new OTP code and returns the code with its plaintext for sending

func (*OTPRepository) DeleteByEmail

func (r *OTPRepository) DeleteByEmail(ctx context.Context, email string) error

DeleteByEmail deletes all OTP codes for an email

func (*OTPRepository) DeleteByPhone

func (r *OTPRepository) DeleteByPhone(ctx context.Context, phone string) error

DeleteByPhone deletes all OTP codes for a phone number

func (*OTPRepository) DeleteExpired

func (r *OTPRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired deletes all expired OTP codes

func (*OTPRepository) GetByCode

func (r *OTPRepository) GetByCode(ctx context.Context, email *string, phone *string, code string) (*OTPCode, error)

GetByCode retrieves an OTP code by email/phone and code. It uses hash-based lookup first, with a plaintext fallback for codes created before the hashing migration.

func (*OTPRepository) IncrementAttempts

func (r *OTPRepository) IncrementAttempts(ctx context.Context, id string) error

IncrementAttempts increments the attempt counter for an OTP code

func (*OTPRepository) MarkAsUsed

func (r *OTPRepository) MarkAsUsed(ctx context.Context, id string) error

MarkAsUsed marks an OTP code as used

func (*OTPRepository) Validate

func (r *OTPRepository) Validate(ctx context.Context, email *string, phone *string, code string) (*OTPCode, error)

Validate validates an OTP code

type OTPRepositoryInterface

type OTPRepositoryInterface interface {
	// Create generates a new OTP for email or phone, returning the code with plaintext for sending
	Create(ctx context.Context, email, phone *string, otpType, purpose string, expiryDuration time.Duration) (*OTPCodeWithPlaintext, error)

	// GetByCode retrieves an OTP by its code and contact info
	GetByCode(ctx context.Context, email, phone *string, code string) (*OTPCode, error)

	// Validate checks if an OTP is valid and not expired
	Validate(ctx context.Context, email, phone *string, code string) (*OTPCode, error)

	// IncrementAttempts increments the verification attempt counter
	IncrementAttempts(ctx context.Context, id string) error

	// MarkAsUsed marks an OTP as used
	MarkAsUsed(ctx context.Context, id string) error

	// DeleteExpired removes expired OTPs (cleanup job)
	DeleteExpired(ctx context.Context) (int64, error)

	// DeleteByEmail removes all OTPs for an email
	DeleteByEmail(ctx context.Context, email string) error

	// DeleteByPhone removes all OTPs for a phone number
	DeleteByPhone(ctx context.Context, phone string) error
}

OTPRepositoryInterface defines OTP (one-time password) operations.

type OTPSender

type OTPSender interface {
	SendEmailOTP(ctx context.Context, to, code, purpose string) error
	SendSMSOTP(ctx context.Context, to, code, purpose string) error
}

OTPSender defines the interface for sending OTP codes

type OTPService

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

OTPService provides OTP functionality

func NewOTPService

func NewOTPService(
	repo *OTPRepository,
	userRepo *UserRepository,
	otpSender OTPSender,
	otpDuration time.Duration,
) *OTPService

NewOTPService creates a new OTP service

func (*OTPService) ResendEmailOTP

func (s *OTPService) ResendEmailOTP(ctx context.Context, email, purpose string) error

ResendEmailOTP resends an OTP code to an email

func (*OTPService) ResendSMSOTP

func (s *OTPService) ResendSMSOTP(ctx context.Context, phone, purpose string) error

ResendSMSOTP resends an OTP code to a phone number

func (*OTPService) SendEmailOTP

func (s *OTPService) SendEmailOTP(ctx context.Context, email, purpose string) error

SendEmailOTP sends an OTP code via email

func (*OTPService) SendSMSOTP

func (s *OTPService) SendSMSOTP(ctx context.Context, phone, purpose string) error

SendSMSOTP sends an OTP code via SMS

func (*OTPService) VerifyEmailOTP

func (s *OTPService) VerifyEmailOTP(ctx context.Context, email, code string) (*OTPCode, error)

VerifyEmailOTP verifies an OTP code sent via email

func (*OTPService) VerifySMSOTP

func (s *OTPService) VerifySMSOTP(ctx context.Context, phone, code string) (*OTPCode, error)

VerifySMSOTP verifies an OTP code sent via SMS

type ParsedLogoutRequest

type ParsedLogoutRequest struct {
	ID           string // Request ID for InResponseTo
	NameID       string // User identifier
	NameIDFormat string // Format of NameID
	SessionIndex string // Session to terminate (optional)
	Issuer       string // IdP that sent the request
	Destination  string // Where response should be sent
	RelayState   string // Optional state to return
}

ParsedLogoutRequest represents a parsed SAML LogoutRequest from IdP

type ParsedLogoutResponse

type ParsedLogoutResponse struct {
	InResponseTo  string // ID of original LogoutRequest
	Status        string // "Success" or error code
	StatusMessage string // Optional status message
	Issuer        string // IdP that sent the response
}

ParsedLogoutResponse represents a parsed SAML LogoutResponse from IdP

type PasswordHasher

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

PasswordHasher handles password hashing and validation

func NewPasswordHasher

func NewPasswordHasher() *PasswordHasher

NewPasswordHasher creates a new password hasher with default settings Default requires uppercase, lowercase, and digit (no symbol for mobile usability)

func NewPasswordHasherWithConfig

func NewPasswordHasherWithConfig(config PasswordHasherConfig) *PasswordHasher

NewPasswordHasherWithConfig creates a password hasher with custom configuration

func (*PasswordHasher) ComparePassword

func (h *PasswordHasher) ComparePassword(hashedPassword, plainPassword string) error

ComparePassword compares a plain password with a hashed password

func (*PasswordHasher) HashPassword

func (h *PasswordHasher) HashPassword(password string) (string, error)

HashPassword hashes a password using bcrypt

func (*PasswordHasher) NeedsRehash

func (h *PasswordHasher) NeedsRehash(hashedPassword string) bool

NeedsRehash checks if a password hash needs to be regenerated with a new cost

func (*PasswordHasher) ValidatePassword

func (h *PasswordHasher) ValidatePassword(password string) error

ValidatePassword validates a password against configured requirements

type PasswordHasherConfig

type PasswordHasherConfig struct {
	Cost          int
	MinLength     int
	RequireUpper  bool
	RequireLower  bool
	RequireDigit  bool
	RequireSymbol bool
}

PasswordHasherConfig configures password requirements

type PasswordResetRepository

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

PasswordResetRepository handles database operations for password reset tokens

func NewPasswordResetRepository

func NewPasswordResetRepository(db *database.Connection) *PasswordResetRepository

NewPasswordResetRepository creates a new password reset repository

func (*PasswordResetRepository) Create

Create creates a new password reset token SECURITY: The plaintext token is returned only once for sending via email. Only the hash is stored.

func (*PasswordResetRepository) DeleteByUserID

func (r *PasswordResetRepository) DeleteByUserID(ctx context.Context, userID string) error

DeleteByUserID deletes all password reset tokens for a user

func (*PasswordResetRepository) DeleteExpired

func (r *PasswordResetRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired deletes all expired password reset tokens

func (*PasswordResetRepository) GetByToken

func (r *PasswordResetRepository) GetByToken(ctx context.Context, token string) (*PasswordResetToken, error)

GetByToken retrieves a password reset token by token SECURITY: The incoming plaintext token is hashed before lookup

func (*PasswordResetRepository) GetLatestByUserID

func (r *PasswordResetRepository) GetLatestByUserID(ctx context.Context, userID string) (*PasswordResetToken, error)

GetLatestByUserID retrieves the most recent password reset token for a user

func (*PasswordResetRepository) MarkAsUsed

func (r *PasswordResetRepository) MarkAsUsed(ctx context.Context, id string) error

MarkAsUsed marks a password reset token as used

func (*PasswordResetRepository) Validate

Validate validates a password reset token

type PasswordResetRepositoryInterface

type PasswordResetRepositoryInterface interface {
	// Create generates a new password reset token for a user
	// Returns PasswordResetTokenWithPlaintext containing the plaintext token (for sending via email)
	// SECURITY: Only the hash is stored in the database
	Create(ctx context.Context, userID string, expiryDuration time.Duration) (*PasswordResetTokenWithPlaintext, error)

	// GetByToken retrieves a password reset token
	// SECURITY: The incoming token is hashed before lookup
	GetByToken(ctx context.Context, token string) (*PasswordResetToken, error)

	// GetLatestByUserID retrieves the most recent password reset token for a user
	GetLatestByUserID(ctx context.Context, userID string) (*PasswordResetToken, error)

	// Validate checks if a password reset token is valid and not expired
	Validate(ctx context.Context, token string) (*PasswordResetToken, error)

	// MarkAsUsed marks a password reset token as used
	MarkAsUsed(ctx context.Context, id string) error

	// DeleteExpired removes expired tokens (cleanup job)
	DeleteExpired(ctx context.Context) (int64, error)

	// DeleteByUserID removes all reset tokens for a user
	DeleteByUserID(ctx context.Context, userID string) error
}

PasswordResetRepositoryInterface defines password reset token operations.

type PasswordResetService

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

PasswordResetService provides password reset functionality

func NewPasswordResetService

func NewPasswordResetService(
	repo PasswordResetRepositoryInterface,
	userRepo UserRepositoryInterface,
	emailSender EmailService,
	tokenExpiry time.Duration,
	baseURL string,
) *PasswordResetService

NewPasswordResetService creates a new password reset service

func (*PasswordResetService) RequestPasswordReset

func (s *PasswordResetService) RequestPasswordReset(ctx context.Context, email string, redirectTo string) error

RequestPasswordReset sends a password reset email to the specified email SECURITY: Uses constant-time-ish processing to prevent email enumeration via timing attacks If redirectTo is provided, the email link will point to that URL instead of the default baseURL.

func (*PasswordResetService) ResetPassword

func (s *PasswordResetService) ResetPassword(ctx context.Context, token, newPassword string) (string, error)

ResetPassword resets a user's password using a valid reset token

func (*PasswordResetService) VerifyPasswordResetToken

func (s *PasswordResetService) VerifyPasswordResetToken(ctx context.Context, token string) error

VerifyPasswordResetToken verifies if a password reset token is valid

type PasswordResetToken

type PasswordResetToken struct {
	ID        string     `json:"id" db:"id"`
	UserID    string     `json:"user_id" db:"user_id"`
	TokenHash string     `json:"-" db:"token_hash"` // SECURITY: Only hash is stored, never exposed in JSON
	ExpiresAt time.Time  `json:"expires_at" db:"expires_at"`
	UsedAt    *time.Time `json:"used_at,omitempty" db:"used_at"`
	CreatedAt time.Time  `json:"created_at" db:"created_at"`
}

PasswordResetToken represents a password reset token

type PasswordResetTokenWithPlaintext

type PasswordResetTokenWithPlaintext struct {
	PasswordResetToken
	PlaintextToken string // The plaintext token to send to the user (not stored)
}

PasswordResetTokenWithPlaintext is returned from Create with the plaintext token for sending via email. The plaintext token is never stored in the database.

type ReCaptchaProvider

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

ReCaptchaProvider implements CAPTCHA verification using Google reCAPTCHA v3

func NewReCaptchaProvider

func NewReCaptchaProvider(secretKey string, scoreThreshold float64, httpClient *http.Client) *ReCaptchaProvider

NewReCaptchaProvider creates a new reCAPTCHA v3 provider

func (*ReCaptchaProvider) Name

func (p *ReCaptchaProvider) Name() string

Name returns the provider name

func (*ReCaptchaProvider) Verify

func (p *ReCaptchaProvider) Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

Verify validates a reCAPTCHA v3 response token

type RefreshTokenRequest

type RefreshTokenRequest struct {
	RefreshToken string `json:"refresh_token"`
}

RefreshTokenRequest represents a token refresh request

type RefreshTokenResponse

type RefreshTokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"` // seconds
}

RefreshTokenResponse represents a successful token refresh

type SAMLAssertion

type SAMLAssertion struct {
	ID           string
	NameID       string
	NameIDFormat string
	SessionIndex string
	Attributes   map[string][]string
	IssueInstant time.Time
	NotBefore    time.Time
	NotOnOrAfter time.Time
}

SAMLAssertion represents parsed SAML assertion data

type SAMLProvider

type SAMLProvider struct {
	ID               string            `json:"id"`
	Name             string            `json:"name"`
	Enabled          bool              `json:"enabled"`
	EntityID         string            `json:"entity_id"`
	AcsURL           string            `json:"acs_url"`
	SloURL           string            `json:"slo_url,omitempty"`     // SP's SLO endpoint
	SsoURL           string            `json:"sso_url"`               // IdP's SSO endpoint
	IdPSloURL        string            `json:"idp_slo_url,omitempty"` // IdP's SLO endpoint (optional)
	Certificate      string            `json:"certificate"`           // IdP's signing certificate
	AttributeMapping map[string]string `json:"attribute_mapping"`
	AutoCreateUsers  bool              `json:"auto_create_users"`
	DefaultRole      string            `json:"default_role"`
	CreatedAt        time.Time         `json:"created_at"`
	UpdatedAt        time.Time         `json:"updated_at"`

	// Security options
	AllowIDPInitiated        bool     `json:"allow_idp_initiated"`         // Allow IdP-initiated SSO (default: false)
	AllowedRedirectHosts     []string `json:"allowed_redirect_hosts"`      // Whitelist for RelayState redirects
	AllowInsecureMetadataURL bool     `json:"allow_insecure_metadata_url"` // Allow HTTP metadata URLs
	RequireLogoutSignature   bool     `json:"require_logout_signature"`    // Require signed SAML logout messages (default: true)

	// Login targeting
	AllowDashboardLogin bool `json:"allow_dashboard_login"` // Allow for dashboard admin SSO
	AllowAppLogin       bool `json:"allow_app_login"`       // Allow for app user authentication

	// Role/Group-based access control
	RequiredGroups    []string `json:"required_groups,omitempty"`     // User must be in at least ONE of these groups (OR logic)
	RequiredGroupsAll []string `json:"required_groups_all,omitempty"` // User must be in ALL of these groups (AND logic)
	DeniedGroups      []string `json:"denied_groups,omitempty"`       // Reject if user is in any of these groups
	GroupAttribute    string   `json:"group_attribute,omitempty"`     // SAML attribute name for groups (default: "groups")

	// SP signing keys for SLO (PEM-encoded)
	SPCertificate string `json:"-"` // PEM-encoded X.509 certificate
	SPPrivateKey  string `json:"-"` // PEM-encoded private key
	// contains filtered or unexported fields
}

SAMLProvider represents a configured SAML Identity Provider

type SAMLService

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

SAMLService manages SAML SSO functionality

func NewSAMLService

func NewSAMLService(db *database.Connection, baseURL string, configs []config.SAMLProviderConfig) (*SAMLService, error)

NewSAMLService creates a new SAML service

func (*SAMLService) AddProviderFromConfig

func (s *SAMLService) AddProviderFromConfig(cfg config.SAMLProviderConfig) error

AddProviderFromConfig adds a SAML provider from configuration

func (*SAMLService) CheckAssertionReplay

func (s *SAMLService) CheckAssertionReplay(ctx context.Context, assertionID string, expiresAt time.Time) (bool, error)

CheckAssertionReplay checks if an assertion ID has been used before (replay attack prevention)

func (*SAMLService) CleanupExpiredAssertions

func (s *SAMLService) CleanupExpiredAssertions(ctx context.Context) error

CleanupExpiredAssertions removes expired assertion IDs from the replay prevention table

func (*SAMLService) CreateSAMLSession

func (s *SAMLService) CreateSAMLSession(ctx context.Context, session *SAMLSession) error

CreateSAMLSession creates a new SAML session for tracking

func (*SAMLService) DeleteSAMLSession

func (s *SAMLService) DeleteSAMLSession(ctx context.Context, sessionID string) error

func (*SAMLService) DeleteSAMLSessionByNameID

func (s *SAMLService) DeleteSAMLSessionByNameID(ctx context.Context, providerName, nameID string) error

func (*SAMLService) DeleteSAMLSessionsByUserID

func (s *SAMLService) DeleteSAMLSessionsByUserID(ctx context.Context, userID string) error

func (*SAMLService) ExtractGroups

func (s *SAMLService) ExtractGroups(providerName string, assertion *SAMLAssertion) []string

ExtractGroups extracts group memberships from SAML assertion

func (*SAMLService) ExtractUserInfo

func (s *SAMLService) ExtractUserInfo(providerName string, assertion *SAMLAssertion) (email, name string, err error)

ExtractUserInfo extracts user information from SAML assertion using attribute mapping

func (*SAMLService) GenerateAuthRequest

func (s *SAMLService) GenerateAuthRequest(providerName string, relayState string) (string, string, error)

GenerateAuthRequest generates a SAML AuthnRequest for the given provider

func (*SAMLService) GenerateLogoutRequest

func (s *SAMLService) GenerateLogoutRequest(providerName, nameID, nameIDFormat, sessionIndex, relayState string) (*LogoutRequestResult, error)

GenerateLogoutRequest generates a signed SAML LogoutRequest for SP-initiated logout

func (*SAMLService) GenerateLogoutResponse

func (s *SAMLService) GenerateLogoutResponse(providerName, inResponseTo, relayState string) (*url.URL, error)

GenerateLogoutResponse generates a signed SAML LogoutResponse for IdP-initiated logout Returns the redirect URL for HTTP-Redirect binding

func (*SAMLService) GetIdPSloURL

func (s *SAMLService) GetIdPSloURL(providerName string) (string, error)

GetIdPSloURL returns the IdP's SLO URL for a provider (if available)

func (*SAMLService) GetProvider

func (s *SAMLService) GetProvider(name string) (*SAMLProvider, error)

GetProvider returns a SAML provider by name

func (*SAMLService) GetProviderForTenant

func (s *SAMLService) GetProviderForTenant(ctx context.Context, name string, tenantID string) (*SAMLProvider, error)

func (*SAMLService) GetProvidersForApp

func (s *SAMLService) GetProvidersForApp() []*SAMLProvider

func (*SAMLService) GetProvidersForAppWithTenant

func (s *SAMLService) GetProvidersForAppWithTenant(ctx context.Context, tenantID string) []*SAMLProvider

func (*SAMLService) GetProvidersForDashboard

func (s *SAMLService) GetProvidersForDashboard() []*SAMLProvider

func (*SAMLService) GetProvidersForDashboardWithTenant

func (s *SAMLService) GetProvidersForDashboardWithTenant(ctx context.Context, tenantID string) []*SAMLProvider

func (*SAMLService) GetSAMLSessionByNameID

func (s *SAMLService) GetSAMLSessionByNameID(ctx context.Context, providerName, nameID string) (*SAMLSession, error)

func (*SAMLService) GetSAMLSessionBySessionIndex

func (s *SAMLService) GetSAMLSessionBySessionIndex(ctx context.Context, providerName, sessionIndex string) (*SAMLSession, error)

func (*SAMLService) GetSAMLSessionByUserID

func (s *SAMLService) GetSAMLSessionByUserID(ctx context.Context, userID string) (*SAMLSession, error)

func (*SAMLService) GetSPMetadata

func (s *SAMLService) GetSPMetadata(providerName string) ([]byte, error)

GetSPMetadata returns the SP metadata XML for a provider

func (*SAMLService) HasSigningKey

func (s *SAMLService) HasSigningKey(providerName string) bool

HasSigningKey returns true if the provider has SP signing keys configured

func (*SAMLService) ListProviders

func (s *SAMLService) ListProviders() []*SAMLProvider

ListProviders returns all enabled SAML providers

func (*SAMLService) LoadProvidersFromDB

func (s *SAMLService) LoadProvidersFromDB(ctx context.Context) error

func (*SAMLService) ParseAssertion

func (s *SAMLService) ParseAssertion(providerName string, samlResponse string) (*SAMLAssertion, error)

ParseAssertion parses and validates a SAML assertion

func (*SAMLService) ParseLogoutRequest

func (s *SAMLService) ParseLogoutRequest(samlRequest, relayState string, isDeflated bool) (*ParsedLogoutRequest, string, error)

ParseLogoutRequest parses a SAML LogoutRequest from IdP (IdP-initiated logout)

func (*SAMLService) ParseLogoutResponse

func (s *SAMLService) ParseLogoutResponse(samlResponse string, isDeflated bool) (*ParsedLogoutResponse, string, error)

ParseLogoutResponse parses a SAML LogoutResponse from IdP (SP-initiated logout callback)

func (*SAMLService) ReloadProviderFromDB

func (s *SAMLService) ReloadProviderFromDB(ctx context.Context, name string) error

func (*SAMLService) RemoveProvider

func (s *SAMLService) RemoveProvider(name string)

func (*SAMLService) ValidateGroupMembership

func (s *SAMLService) ValidateGroupMembership(provider *SAMLProvider, groups []string) error

ValidateGroupMembership validates user's group membership against provider's RBAC rules

type SAMLSession

type SAMLSession struct {
	ID           string                 `json:"id"`
	UserID       string                 `json:"user_id"`
	ProviderID   string                 `json:"provider_id,omitempty"`
	ProviderName string                 `json:"provider_name"`
	NameID       string                 `json:"name_id"`
	NameIDFormat string                 `json:"name_id_format,omitempty"`
	SessionIndex string                 `json:"session_index,omitempty"`
	Attributes   map[string]interface{} `json:"attributes,omitempty"`
	ExpiresAt    *time.Time             `json:"expires_at,omitempty"`
	CreatedAt    time.Time              `json:"created_at"`
}

SAMLSession represents an active SAML authentication session

type SAMLSessionStore

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

func NewSAMLSessionStore

func NewSAMLSessionStore(db *database.Connection) *SAMLSessionStore

func (*SAMLSessionStore) CleanupExpiredAssertions

func (ss *SAMLSessionStore) CleanupExpiredAssertions(ctx context.Context) error

func (*SAMLSessionStore) CreateSAMLSession

func (ss *SAMLSessionStore) CreateSAMLSession(ctx context.Context, session *SAMLSession) error

func (*SAMLSessionStore) DeleteSAMLSession

func (ss *SAMLSessionStore) DeleteSAMLSession(ctx context.Context, sessionID string) error

func (*SAMLSessionStore) DeleteSAMLSessionByNameID

func (ss *SAMLSessionStore) DeleteSAMLSessionByNameID(ctx context.Context, providerName, nameID string) error

func (*SAMLSessionStore) DeleteSAMLSessionsByUserID

func (ss *SAMLSessionStore) DeleteSAMLSessionsByUserID(ctx context.Context, userID string) error

func (*SAMLSessionStore) GetSAMLSessionByNameID

func (ss *SAMLSessionStore) GetSAMLSessionByNameID(ctx context.Context, providerName, nameID string) (*SAMLSession, error)

func (*SAMLSessionStore) GetSAMLSessionBySessionIndex

func (ss *SAMLSessionStore) GetSAMLSessionBySessionIndex(ctx context.Context, providerName, sessionIndex string) (*SAMLSession, error)

func (*SAMLSessionStore) GetSAMLSessionByUserID

func (ss *SAMLSessionStore) GetSAMLSessionByUserID(ctx context.Context, userID string) (*SAMLSession, error)

type SSOIdentity

type SSOIdentity struct {
	ID             uuid.UUID `json:"id"`
	UserID         uuid.UUID `json:"user_id"`
	Provider       string    `json:"provider"`
	ProviderUserID string    `json:"provider_user_id"`
	Email          *string   `json:"email,omitempty"`
	CreatedAt      time.Time `json:"created_at"`
}

SSOIdentity represents a linked SSO identity for a dashboard user

type SecurityEvent

type SecurityEvent struct {
	Type      SecurityEventType
	UserID    string
	Email     string
	IPAddress string
	UserAgent string
	Details   map[string]interface{}
}

SecurityEvent represents a security event to be logged

type SecurityEventType

type SecurityEventType string

SecurityEventType represents the type of security event

const (
	// Login events
	SecurityEventLoginSuccess    SecurityEventType = "login_success"
	SecurityEventLoginFailed     SecurityEventType = "login_failed"
	SecurityEventAccountLocked   SecurityEventType = "account_locked"
	SecurityEventAccountUnlocked SecurityEventType = "account_unlocked"
	SecurityEventLogout          SecurityEventType = "logout"

	// Token events
	SecurityEventTokenRefresh SecurityEventType = "token_refresh"
	SecurityEventTokenRevoked SecurityEventType = "token_revoked"
	SecurityEventInvalidToken SecurityEventType = "invalid_token"

	// Password events
	SecurityEventPasswordReset   SecurityEventType = "password_reset_requested"
	SecurityEventPasswordChanged SecurityEventType = "password_changed"

	// 2FA events
	SecurityEvent2FAEnabled  SecurityEventType = "2fa_enabled"
	SecurityEvent2FADisabled SecurityEventType = "2fa_disabled"
	SecurityEvent2FAVerified SecurityEventType = "2fa_verified"
	SecurityEvent2FAFailed   SecurityEventType = "2fa_failed"

	// Impersonation events
	SecurityEventImpersonationStart SecurityEventType = "impersonation_start"
	SecurityEventImpersonationEnd   SecurityEventType = "impersonation_end"

	// Suspicious activity
	SecurityEventSuspiciousActivity SecurityEventType = "suspicious_activity"
	SecurityEventRateLimitExceeded  SecurityEventType = "rate_limit_exceeded"
)

type SecurityLogger

type SecurityLogger struct{}

SecurityLogger handles logging of security events

func NewSecurityLogger

func NewSecurityLogger() *SecurityLogger

NewSecurityLogger creates a new security logger

func (*SecurityLogger) Log

func (s *SecurityLogger) Log(ctx context.Context, event SecurityEvent)

Log logs a security event All security events are logged at INFO level with a "security_event" marker so they can be easily filtered and monitored

func (*SecurityLogger) LogWarning

func (s *SecurityLogger) LogWarning(ctx context.Context, event SecurityEvent)

LogWarning logs a warning-level security event (suspicious activity)

type Service

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

Service provides a high-level authentication API

func NewService

func NewService(
	db *database.Connection,
	cfg *config.AuthConfig,
	emailService interface{},
	baseURL string,
) *Service

NewService creates a new authentication service

func NewTestAuthServiceWithSettings

func NewTestAuthServiceWithSettings(signupEnabled, passwordLoginEnabled bool) *Service

NewTestAuthServiceWithSettings creates a Service with pre-configured settings for testing

func (*Service) CleanupExpiredNonces

func (s *Service) CleanupExpiredNonces(ctx context.Context) (int64, error)

func (*Service) CreateSAMLUser

func (s *Service) CreateSAMLUser(ctx context.Context, email, name, provider, nameID string, attrs map[string][]string) (*User, error)

CreateSAMLUser creates a new user from a SAML assertion

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, email, password string) (*User, error)

CreateUser creates a new user with email and optional password

func (*Service) DisableTOTP

func (s *Service) DisableTOTP(ctx context.Context, userID, password string) error

DisableTOTP disables 2FA for a user

func (*Service) EmergencyRevokeAllServiceRoleTokens

func (s *Service) EmergencyRevokeAllServiceRoleTokens(ctx context.Context, revokedBy, reason string) (int64, error)

EmergencyRevokeAllServiceRoleTokens revokes ALL service_role tokens globally This should be used in security emergencies when service_role keys may be compromised Returns the ID of the revocation record for audit purposes

func (*Service) EmergencyRevokeServiceRoleToken

func (s *Service) EmergencyRevokeServiceRoleToken(ctx context.Context, jti, revokedBy, reason string) error

EmergencyRevokeServiceRoleToken revokes a specific service_role token by JTI This allows selective revocation of individual compromised tokens

func (*Service) EnableTOTP

func (s *Service) EnableTOTP(ctx context.Context, userID, code string) ([]string, error)

EnableTOTP enables 2FA after verifying the TOTP code

func (*Service) GenerateTokensForSAMLUser

func (s *Service) GenerateTokensForSAMLUser(ctx context.Context, user *User) (*SignInResponse, error)

GenerateTokensForSAMLUser generates tokens for a SAML-authenticated user This is a wrapper around GenerateTokensForUser that takes a User object

func (*Service) GenerateTokensForUser

func (s *Service) GenerateTokensForUser(ctx context.Context, userID string) (*SignInResponse, error)

GenerateTokensForUser generates JWT tokens for a user after successful 2FA verification

func (*Service) GetAccessTokenExpirySeconds

func (s *Service) GetAccessTokenExpirySeconds() int64

GetAccessTokenExpirySeconds returns the configured JWT access token expiry in seconds

func (*Service) GetActiveImpersonation

func (s *Service) GetActiveImpersonation(ctx context.Context, adminUserID string) (*ImpersonationSession, error)

GetActiveImpersonation gets the active impersonation session for an admin

func (*Service) GetOAuthManager

func (s *Service) GetOAuthManager() *OAuthManager

GetOAuthManager returns the OAuth manager for configuring providers

func (*Service) GetSettingsCache

func (s *Service) GetSettingsCache() *SettingsCache

GetSettingsCache returns the settings cache

func (*Service) GetUser

func (s *Service) GetUser(ctx context.Context, accessToken string) (*User, error)

GetUser retrieves the current user by access token

func (*Service) GetUserByEmail

func (s *Service) GetUserByEmail(ctx context.Context, email string) (*User, error)

GetUserByEmail retrieves a user by email

func (*Service) GetUserIdentities

func (s *Service) GetUserIdentities(ctx context.Context, userID string) ([]UserIdentity, error)

GetUserIdentities retrieves all OAuth identities linked to a user

func (*Service) IsEmailVerificationRequired

func (s *Service) IsEmailVerificationRequired(ctx context.Context) bool

IsEmailVerificationRequired checks if email verification is required based on settings and email configuration

func (*Service) IsServiceRoleTokenRevoked

func (s *Service) IsServiceRoleTokenRevoked(ctx context.Context, jti string) (bool, error)

IsServiceRoleTokenRevoked checks if a service_role token has been emergency revoked This provides a mechanism to revoke compromised service_role tokens immediately without waiting for token expiry

func (*Service) IsSignupEnabled

func (s *Service) IsSignupEnabled() bool

IsSignupEnabled returns whether user signup is enabled

func (*Service) IsTOTPEnabled

func (s *Service) IsTOTPEnabled(ctx context.Context, userID string) (bool, error)

IsTOTPEnabled checks if 2FA is enabled for a user

func (*Service) IsTokenRevoked

func (s *Service) IsTokenRevoked(ctx context.Context, jti string) (bool, error)

IsTokenRevoked checks if a JWT token has been revoked This is a convenience wrapper that only checks exact JTI revocation For full revocation checking including user-wide revocation, use IsTokenRevokedWithClaims

func (*Service) IsTokenRevokedWithClaims

func (s *Service) IsTokenRevokedWithClaims(ctx context.Context, jti string, userID string, tokenIssuedAt time.Time) (bool, error)

IsTokenRevokedWithClaims checks if a JWT token has been revoked It checks both exact JTI revocation and user-wide revocation This is the preferred method for token revocation checking

func (*Service) LinkIdentity

func (s *Service) LinkIdentity(ctx context.Context, userID, provider string) (string, string, error)

LinkIdentity initiates OAuth flow to link a new provider

func (*Service) LinkSAMLIdentity

func (s *Service) LinkSAMLIdentity(ctx context.Context, userID, provider, nameID string, attrs map[string][]string) error

LinkSAMLIdentity links or updates a SAML identity for a user

func (*Service) ListImpersonationSessions

func (s *Service) ListImpersonationSessions(ctx context.Context, adminUserID string, limit, offset int) ([]*ImpersonationSession, error)

ListImpersonationSessions lists impersonation sessions for audit purposes

func (*Service) Reauthenticate

func (s *Service) Reauthenticate(ctx context.Context, userID string) (string, error)

func (*Service) RefreshToken

func (s *Service) RefreshToken(ctx context.Context, req RefreshTokenRequest) (*RefreshTokenResponse, error)

RefreshToken generates new access and refresh tokens using a refresh token (token rotation) SECURITY: Implements refresh token rotation - each refresh generates a new refresh token and invalidates the old one. This limits the window of opportunity for stolen tokens.

func (*Service) RequestPasswordReset

func (s *Service) RequestPasswordReset(ctx context.Context, email string, redirectTo string) error

RequestPasswordReset sends a password reset email If redirectTo is provided, the email link will point to that URL instead of the default.

func (*Service) ResendOTP

func (s *Service) ResendOTP(ctx context.Context, email, purpose string) error

ResendOTP resends an OTP code to an email

func (*Service) ResetPassword

func (s *Service) ResetPassword(ctx context.Context, token, newPassword string) (string, error)

ResetPassword resets a user's password using a valid reset token

func (*Service) RevokeAllUserTokens

func (s *Service) RevokeAllUserTokens(ctx context.Context, userID, reason string) error

RevokeAllUserTokens revokes all tokens for a specific user

func (*Service) RevokeToken

func (s *Service) RevokeToken(ctx context.Context, token, reason string) error

RevokeToken revokes a specific JWT token

func (*Service) SendEmailVerification

func (s *Service) SendEmailVerification(ctx context.Context, userID, email string) error

SendEmailVerification sends a verification email to the user

func (s *Service) SendMagicLink(ctx context.Context, email string) error

SendMagicLink sends a magic link to the specified email

func (*Service) SendOTP

func (s *Service) SendOTP(ctx context.Context, email, purpose string) error

SendOTP sends an OTP code via email

func (*Service) SetEncryptionKey

func (s *Service) SetEncryptionKey(key string)

SetEncryptionKey sets the encryption key for encrypting sensitive data at rest

func (*Service) SetMetrics

func (s *Service) SetMetrics(m *observability.Metrics)

SetMetrics sets the metrics instance for recording auth metrics

func (*Service) SetTOTPRateLimiter

func (s *Service) SetTOTPRateLimiter(limiter *TOTPRateLimiter)

SetTOTPRateLimiter sets the TOTP rate limiter for protecting against brute force attacks

func (*Service) SetupTOTP

func (s *Service) SetupTOTP(ctx context.Context, userID string, issuer string) (*TOTPSetupResponse, error)

SetupTOTP generates a new TOTP secret for 2FA setup

func (*Service) SignIn

func (s *Service) SignIn(ctx context.Context, req SignInRequest) (*SignInResponse, error)

SignIn authenticates a user with email and password

func (*Service) SignInWithIDToken

func (s *Service) SignInWithIDToken(ctx context.Context, provider, idToken, nonce string) (*SignInResponse, error)

SignInWithIDToken signs in a user with an OAuth ID token (Google, Apple, Microsoft, or custom OIDC)

func (*Service) SignOut

func (s *Service) SignOut(ctx context.Context, accessToken string) error

SignOut logs out a user by invalidating their session

func (*Service) SignUp

func (s *Service) SignUp(ctx context.Context, req SignUpRequest) (*SignUpResponse, error)

SignUp registers a new user with email and password

func (*Service) StartAnonImpersonation

func (s *Service) StartAnonImpersonation(ctx context.Context, adminUserID string, tenantID string, reason string, ipAddress string, userAgent string) (*StartImpersonationResponse, error)

StartAnonImpersonation starts an impersonation session as anonymous user

func (*Service) StartImpersonation

func (s *Service) StartImpersonation(ctx context.Context, adminUserID string, tenantID string, req StartImpersonationRequest) (*StartImpersonationResponse, error)

StartImpersonation starts an admin impersonation session

func (*Service) StartServiceImpersonation

func (s *Service) StartServiceImpersonation(ctx context.Context, adminUserID string, tenantID string, reason string, ipAddress string, userAgent string) (*StartImpersonationResponse, error)

StartServiceImpersonation starts an impersonation session with service role

func (*Service) StopImpersonation

func (s *Service) StopImpersonation(ctx context.Context, adminUserID string) error

StopImpersonation stops the active impersonation session for an admin

func (*Service) UnlinkIdentity

func (s *Service) UnlinkIdentity(ctx context.Context, userID, identityID string) error

UnlinkIdentity removes an OAuth identity from a user

func (*Service) UpdateUser

func (s *Service) UpdateUser(ctx context.Context, userID string, req UpdateUserRequest) (*User, error)

UpdateUser updates user information

func (*Service) ValidateServiceRoleToken

func (s *Service) ValidateServiceRoleToken(token string) (*TokenClaims, error)

ValidateServiceRoleToken validates a JWT containing a role claim (anon, service_role, authenticated) This is used for client keys which are JWTs with role claims. Unlike user tokens, these don't require user lookup or revocation checks.

func (*Service) ValidateToken

func (s *Service) ValidateToken(token string) (*TokenClaims, error)

ValidateToken validates an access token and returns the claims

func (*Service) ValidateTokenWithSecret

func (s *Service) ValidateTokenWithSecret(token, secretKey string) (*TokenClaims, error)

ValidateTokenWithSecret validates an access token using a specific secret key This is used for multi-tenant scenarios where each tenant may have a different JWT secret

func (*Service) VerifyEmailToken

func (s *Service) VerifyEmailToken(ctx context.Context, token string) (*User, error)

VerifyEmailToken validates the verification token and marks the user's email as verified

func (s *Service) VerifyMagicLink(ctx context.Context, token string) (*SignInResponse, error)

VerifyMagicLink verifies a magic link and returns tokens

func (*Service) VerifyNonce

func (s *Service) VerifyNonce(ctx context.Context, nonce, userID string) bool

func (*Service) VerifyOTP

func (s *Service) VerifyOTP(ctx context.Context, email, code string) (*OTPCode, error)

VerifyOTP verifies an OTP code sent via email

func (*Service) VerifyPasswordResetToken

func (s *Service) VerifyPasswordResetToken(ctx context.Context, token string) error

VerifyPasswordResetToken verifies if a password reset token is valid

func (*Service) VerifyTOTP

func (s *Service) VerifyTOTP(ctx context.Context, userID, code string) error

VerifyTOTP verifies a TOTP code during login

func (*Service) VerifyTOTPWithContext

func (s *Service) VerifyTOTPWithContext(ctx context.Context, userID, code, ipAddress, userAgent string) error

VerifyTOTPWithContext verifies a TOTP code with IP address and user agent for rate limiting

type Session

type Session struct {
	ID           string    `json:"id" db:"id"`
	UserID       string    `json:"user_id" db:"user_id"`
	AccessToken  string    `json:"access_token" db:"access_token"`
	RefreshToken string    `json:"refresh_token" db:"refresh_token"`
	ExpiresAt    time.Time `json:"expires_at" db:"expires_at"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
}

Session represents a user session

type SessionRepository

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

SessionRepository handles database operations for sessions

func NewSessionRepository

func NewSessionRepository(db *database.Connection) *SessionRepository

NewSessionRepository creates a new session repository

func (*SessionRepository) Count

func (r *SessionRepository) Count(ctx context.Context) (int, error)

Count returns the total number of active sessions

func (*SessionRepository) CountByUserID

func (r *SessionRepository) CountByUserID(ctx context.Context, userID string) (int, error)

CountByUserID returns the number of active sessions for a user

func (*SessionRepository) Create

func (r *SessionRepository) Create(ctx context.Context, userID, accessToken, refreshToken string, expiresAt time.Time) (*Session, error)

Create creates a new session SECURITY: Tokens are hashed before storage. Plaintext tokens are returned to caller but never stored.

func (*SessionRepository) Delete

func (r *SessionRepository) Delete(ctx context.Context, id string) error

Delete deletes a session by ID

func (*SessionRepository) DeleteByAccessToken

func (r *SessionRepository) DeleteByAccessToken(ctx context.Context, accessToken string) error

DeleteByAccessToken deletes a session by access token SECURITY: Token is hashed for lookup.

func (*SessionRepository) DeleteByUserID

func (r *SessionRepository) DeleteByUserID(ctx context.Context, userID string) error

DeleteByUserID deletes all sessions for a user

func (*SessionRepository) DeleteExpired

func (r *SessionRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired deletes all expired sessions

func (*SessionRepository) GetByAccessToken

func (r *SessionRepository) GetByAccessToken(ctx context.Context, accessToken string) (*Session, error)

GetByAccessToken retrieves a session by access token SECURITY: The token is hashed and compared against stored hashes.

func (*SessionRepository) GetByRefreshToken

func (r *SessionRepository) GetByRefreshToken(ctx context.Context, refreshToken string) (*Session, error)

GetByRefreshToken retrieves a session by refresh token SECURITY: The token is hashed and compared against stored hashes.

func (*SessionRepository) GetByUserID

func (r *SessionRepository) GetByUserID(ctx context.Context, userID string) ([]*Session, error)

GetByUserID retrieves all sessions for a user NOTE: Tokens are not returned since we only store hashes.

func (*SessionRepository) ListAll

func (r *SessionRepository) ListAll(ctx context.Context, includeExpired bool) ([]SessionWithUser, error)

ListAll returns all sessions with user info for admin views

func (*SessionRepository) ListAllPaginated

func (r *SessionRepository) ListAllPaginated(ctx context.Context, includeExpired bool, limit, offset int) ([]SessionWithUser, int, error)

ListAllPaginated returns paginated sessions with user info for admin views

func (*SessionRepository) UpdateAccessToken

func (r *SessionRepository) UpdateAccessToken(ctx context.Context, id, accessToken string) error

UpdateAccessToken updates only the access token SECURITY: Token is hashed before storage.

func (*SessionRepository) UpdateTokens

func (r *SessionRepository) UpdateTokens(ctx context.Context, id, accessToken, refreshToken string, expiresAt time.Time) error

UpdateTokens updates the tokens for a session SECURITY: Tokens are hashed before storage.

type SessionRepositoryInterface

type SessionRepositoryInterface interface {
	// Create creates a new session for a user
	// Note: Tokens should be hashed before storage
	Create(ctx context.Context, userID, accessToken, refreshToken string, expiresAt time.Time) (*Session, error)

	// GetByAccessToken retrieves a session by its access token
	// Note: Token should be hashed for comparison
	GetByAccessToken(ctx context.Context, accessToken string) (*Session, error)

	// GetByRefreshToken retrieves a session by its refresh token
	// Note: Token should be hashed for comparison
	GetByRefreshToken(ctx context.Context, refreshToken string) (*Session, error)

	// GetByUserID retrieves all sessions for a user
	GetByUserID(ctx context.Context, userID string) ([]*Session, error)

	// UpdateTokens updates the tokens and expiry for a session
	UpdateTokens(ctx context.Context, id, accessToken, refreshToken string, expiresAt time.Time) error

	// Delete removes a session by ID
	Delete(ctx context.Context, id string) error

	// DeleteByAccessToken removes a session by its access token
	DeleteByAccessToken(ctx context.Context, accessToken string) error

	// DeleteByUserID removes all sessions for a user
	DeleteByUserID(ctx context.Context, userID string) error

	// DeleteExpired removes all expired sessions (cleanup job)
	DeleteExpired(ctx context.Context) (int64, error)

	// Count returns the total number of active sessions
	Count(ctx context.Context) (int, error)
}

SessionRepositoryInterface defines session data operations. Sessions track active user authentication states.

type SessionWithUser

type SessionWithUser struct {
	ID        string    `json:"id"`
	UserID    string    `json:"user_id"`
	ExpiresAt time.Time `json:"expires_at"`
	CreatedAt time.Time `json:"created_at"`
	UserEmail *string   `json:"user_email,omitempty"`
}

SessionWithUser represents a session with user info for admin views

type SettingsCache

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

SettingsCache provides a simple in-memory cache for settings with TTL It supports environment variable overrides that take precedence over database values

func NewSettingsCache

func NewSettingsCache(service *SystemSettingsService, ttl time.Duration) *SettingsCache

NewSettingsCache creates a new settings cache

func (*SettingsCache) GetBool

func (c *SettingsCache) GetBool(ctx context.Context, key string, defaultValue bool) bool

GetBool retrieves a boolean setting with caching Priority: Environment variables > Cache > Database > Viper config > Default value

func (*SettingsCache) GetDuration

func (c *SettingsCache) GetDuration(ctx context.Context, key string, defaultValue time.Duration) time.Duration

GetDuration retrieves a duration setting with caching Duration values are stored as strings and parsed using time.ParseDuration Priority: Environment variables > Cache > Database > Default value

func (*SettingsCache) GetEnvVarName

func (c *SettingsCache) GetEnvVarName(key string) string

GetEnvVarName returns the environment variable name for a given setting key e.g., "app.auth.signup_enabled" -> "FLUXBASE_AUTH_SIGNUP_ENABLED" e.g., "app.realtime.enabled" -> "FLUXBASE_REALTIME_ENABLED"

func (*SettingsCache) GetInt

func (c *SettingsCache) GetInt(ctx context.Context, key string, defaultValue int) int

GetInt retrieves an integer setting with caching Priority: Environment variables > Cache > Database > Viper config > Default value

func (*SettingsCache) GetJSON

func (c *SettingsCache) GetJSON(ctx context.Context, key string, target interface{}) error

GetJSON retrieves a JSON setting and unmarshals it into the target Priority: Environment variables > Cache > Database > Error

func (*SettingsCache) GetMany

func (c *SettingsCache) GetMany(ctx context.Context, keys []string) (map[string]interface{}, error)

GetMany retrieves multiple settings at once Returns a map of key -> value (the actual setting value, not the full setting object) Missing or unauthorized settings are omitted from the result (no error)

func (*SettingsCache) GetString

func (c *SettingsCache) GetString(ctx context.Context, key string, defaultValue string) string

GetString retrieves a string setting with caching Priority: Environment variables > Cache > Database > Viper config > Default value

func (*SettingsCache) Invalidate

func (c *SettingsCache) Invalidate(key string)

Invalidate removes a key from the cache

func (*SettingsCache) InvalidateAll

func (c *SettingsCache) InvalidateAll()

InvalidateAll clears the entire cache

func (*SettingsCache) IsOverriddenByEnv

func (c *SettingsCache) IsOverriddenByEnv(key string) bool

IsOverriddenByEnv checks if a setting is overridden by an environment variable

type SetupCompleteValue

type SetupCompleteValue struct {
	Completed       bool       `json:"completed"`
	CompletedAt     time.Time  `json:"completed_at"`
	FirstAdminID    *uuid.UUID `json:"first_admin_id,omitempty"`
	FirstAdminEmail *string    `json:"first_admin_email,omitempty"`
}

SetupCompleteValue represents the value stored for setup_completed setting

type SignInRequest

type SignInRequest struct {
	Email             string `json:"email"`
	Password          string `json:"password"`
	CaptchaToken      string `json:"captcha_token,omitempty"`      // CAPTCHA verification token
	ChallengeID       string `json:"challenge_id,omitempty"`       // Challenge ID from pre-flight check
	DeviceFingerprint string `json:"device_fingerprint,omitempty"` // Optional device fingerprint for trust tracking
}

SignInRequest represents a login request

type SignInResponse

type SignInResponse struct {
	User         *User  `json:"user"`
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"` // seconds
}

SignInResponse represents a successful login response

type SignUpRequest

type SignUpRequest struct {
	Email             string                 `json:"email"`
	Password          string                 `json:"password"`
	UserMetadata      map[string]interface{} `json:"user_metadata,omitempty"`      // User-editable metadata
	AppMetadata       map[string]interface{} `json:"app_metadata,omitempty"`       // Application/admin-only metadata
	CaptchaToken      string                 `json:"captcha_token,omitempty"`      // CAPTCHA verification token
	ChallengeID       string                 `json:"challenge_id,omitempty"`       // Challenge ID from pre-flight check
	DeviceFingerprint string                 `json:"device_fingerprint,omitempty"` // Optional device fingerprint for trust tracking
}

SignUpRequest represents a user registration request

type SignUpResponse

type SignUpResponse struct {
	User                      *User  `json:"user"`
	AccessToken               string `json:"access_token,omitempty"`
	RefreshToken              string `json:"refresh_token,omitempty"`
	ExpiresIn                 int64  `json:"expires_in,omitempty"` // seconds
	RequiresEmailVerification bool   `json:"requires_email_verification,omitempty"`
}

SignUpResponse represents a successful registration response

type SignUpValidator

type SignUpValidator struct{}

SignUpValidator validates signup requests

func (*SignUpValidator) Validate

func (v *SignUpValidator) Validate(email, password string) error

Validate validates a signup request

type StartImpersonationRequest

type StartImpersonationRequest struct {
	TargetUserID string `json:"target_user_id"`
	Reason       string `json:"reason"`
	IPAddress    string `json:"-"`
	UserAgent    string `json:"-"`
}

type StartImpersonationResponse

type StartImpersonationResponse struct {
	Session      *ImpersonationSession `json:"session"`
	TargetUser   *User                 `json:"target_user"`
	AccessToken  string                `json:"access_token"`
	RefreshToken string                `json:"refresh_token"`
	ExpiresIn    int64                 `json:"expires_in"`
}

type StateMetadata

type StateMetadata struct {
	Expiry       time.Time
	RedirectURI  string // Optional custom redirect URI for this OAuth flow
	Provider     string // OAuth provider name
	CodeVerifier string // PKCE code verifier
	Nonce        string // OpenID Connect nonce
}

StateMetadata holds metadata associated with an OAuth state

type StateStore

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

StateStore manages OAuth state tokens for CSRF protection Uses a mutex to protect concurrent access from multiple goroutines

func NewStateStore

func NewStateStore() *StateStore

NewStateStore creates a new state store

func (*StateStore) Cleanup

func (s *StateStore) Cleanup(ctx context.Context) error

Cleanup removes expired state tokens (implements StateStorer)

func (*StateStore) GetAndValidate

func (s *StateStore) GetAndValidate(ctx context.Context, state string) (*StateMetadata, bool)

GetAndValidate checks if a state token is valid, removes it, and returns the metadata (implements StateStorer) Returns the metadata and a boolean indicating if the state was valid

func (*StateStore) Set

func (s *StateStore) Set(ctx context.Context, state string, metadata StateMetadata) error

Set stores a state token with metadata (implements StateStorer)

func (*StateStore) Validate

func (s *StateStore) Validate(ctx context.Context, state string) bool

Validate checks if a state token is valid and removes it (implements StateStorer)

type StateStorer

type StateStorer interface {
	// Set stores a state token with optional metadata
	Set(ctx context.Context, state string, metadata StateMetadata) error
	// Validate checks if a state token is valid and removes it
	Validate(ctx context.Context, state string) bool
	// GetAndValidate validates and returns metadata, removing the state
	GetAndValidate(ctx context.Context, state string) (*StateMetadata, bool)
	// Cleanup removes expired state tokens
	Cleanup(ctx context.Context) error
}

StateStorer is the interface for OAuth state storage Implementations can be in-memory (StateStore) or database-backed (DBStateStore)

type StoredOAuthToken

type StoredOAuthToken struct {
	ID           string
	UserID       string
	Provider     string
	AccessToken  string
	RefreshToken string
	IDToken      string
	TokenExpiry  time.Time
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

StoredOAuthToken represents an OAuth token stored in the database

type SystemSetting

type SystemSetting struct {
	ID             uuid.UUID              `json:"id"`
	Key            string                 `json:"key"`
	Value          map[string]interface{} `json:"value"`
	Description    *string                `json:"description,omitempty"`
	IsOverridden   bool                   `json:"is_overridden"`
	OverrideSource string                 `json:"override_source,omitempty"`
	CreatedAt      time.Time              `json:"created_at"`
	UpdatedAt      time.Time              `json:"updated_at"`
}

SystemSetting represents a system-wide configuration setting

type SystemSettingsService

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

SystemSettingsService handles system-wide settings

func NewSystemSettingsService

func NewSystemSettingsService(db *database.Connection) *SystemSettingsService

NewSystemSettingsService creates a new system settings service

func (*SystemSettingsService) DeleteInstanceSetting

func (s *SystemSettingsService) DeleteInstanceSetting(ctx context.Context, key string) error

DeleteInstanceSetting removes an instance-level setting

func (*SystemSettingsService) DeleteSetting

func (s *SystemSettingsService) DeleteSetting(ctx context.Context, key string) error

DeleteSetting removes a system setting by key

func (*SystemSettingsService) GetInstanceSetting

func (s *SystemSettingsService) GetInstanceSetting(ctx context.Context, key string) (*InstanceSetting, error)

GetInstanceSetting retrieves an instance-level setting from app.instance_settings

func (*SystemSettingsService) GetSetting

func (s *SystemSettingsService) GetSetting(ctx context.Context, key string) (*SystemSetting, error)

GetSetting retrieves a system setting by key

func (*SystemSettingsService) GetSettingWithInheritance

func (s *SystemSettingsService) GetSettingWithInheritance(ctx context.Context, key string, tenantID string) (*SystemSetting, error)

GetSettingWithInheritance retrieves a setting with inheritance logic Priority: tenant settings > instance settings > error

func (*SystemSettingsService) GetSettings

func (s *SystemSettingsService) GetSettings(ctx context.Context, keys []string) (map[string]*SystemSetting, error)

GetSettings retrieves multiple settings at once using a batch query Returns a map of key -> setting for all found settings

func (*SystemSettingsService) GetSetupInfo

GetSetupInfo retrieves setup completion information

func (*SystemSettingsService) GetTenantSetting

func (s *SystemSettingsService) GetTenantSetting(ctx context.Context, key string, tenantID string) (*SystemSetting, error)

GetTenantSetting retrieves a tenant-level setting from app.settings

func (*SystemSettingsService) IsSetupComplete

func (s *SystemSettingsService) IsSetupComplete(ctx context.Context) (bool, error)

IsSetupComplete checks if the initial setup has been completed

func (*SystemSettingsService) ListSettings

func (s *SystemSettingsService) ListSettings(ctx context.Context) ([]SystemSetting, error)

ListSettings retrieves all system settings

func (*SystemSettingsService) MarkSetupComplete

func (s *SystemSettingsService) MarkSetupComplete(ctx context.Context, adminID uuid.UUID, adminEmail string) error

MarkSetupComplete marks the setup as completed

func (*SystemSettingsService) SetCache

func (s *SystemSettingsService) SetCache(cache *SettingsCache)

SetCache sets the settings cache for invalidation on updates

func (*SystemSettingsService) SetInstanceSetting

func (s *SystemSettingsService) SetInstanceSetting(ctx context.Context, key string, value map[string]interface{}, description string) error

SetInstanceSetting creates or updates an instance-level setting

func (*SystemSettingsService) SetSetting

func (s *SystemSettingsService) SetSetting(ctx context.Context, key string, value map[string]interface{}, description string) error

SetSetting creates or updates a system setting

func (*SystemSettingsService) SetTenantSetting

func (s *SystemSettingsService) SetTenantSetting(ctx context.Context, key string, tenantID string, value map[string]interface{}, description string) error

SetTenantSetting creates or updates a tenant-level setting

type TOTPRateLimiter

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

TOTPRateLimiter provides rate limiting for TOTP verification attempts

func NewTOTPRateLimiter

func NewTOTPRateLimiter(db *database.Connection, config TOTPRateLimiterConfig) *TOTPRateLimiter

NewTOTPRateLimiter creates a new TOTP rate limiter

func (*TOTPRateLimiter) CheckRateLimit

func (r *TOTPRateLimiter) CheckRateLimit(ctx context.Context, userID string) error

CheckRateLimit checks if the user has exceeded the TOTP attempt limit. Returns nil if the user is allowed to attempt, or ErrTOTPRateLimitExceeded if blocked.

func (*TOTPRateLimiter) ClearFailedAttempts

func (r *TOTPRateLimiter) ClearFailedAttempts(ctx context.Context, userID string) error

ClearFailedAttempts clears all failed TOTP attempts for a user. This can be called after a successful password reset or by an admin.

func (*TOTPRateLimiter) GetFailedAttemptCount

func (r *TOTPRateLimiter) GetFailedAttemptCount(ctx context.Context, userID string) (int, error)

GetFailedAttemptCount returns the number of recent failed TOTP attempts for a user.

func (*TOTPRateLimiter) RecordAttempt

func (r *TOTPRateLimiter) RecordAttempt(ctx context.Context, userID string, success bool, ipAddress, userAgent string) error

RecordAttempt records a TOTP verification attempt in the database. This should be called after every verification attempt (success or failure).

type TOTPRateLimiterConfig

type TOTPRateLimiterConfig struct {
	MaxAttempts     int           // Maximum failed attempts allowed (default: 5)
	WindowDuration  time.Duration // Time window for counting attempts (default: 5 minutes)
	LockoutDuration time.Duration // How long to lock out after exceeding limit (default: 15 minutes)
}

TOTPRateLimiterConfig holds configuration for the TOTP rate limiter

func DefaultTOTPRateLimiterConfig

func DefaultTOTPRateLimiterConfig() TOTPRateLimiterConfig

DefaultTOTPRateLimiterConfig returns the default rate limiter configuration

type TOTPSetupResponse

type TOTPSetupResponse struct {
	ID   string `json:"id"`
	Type string `json:"type"`
	TOTP struct {
		QRCode string `json:"qr_code"`
		Secret string `json:"secret"`
		URI    string `json:"uri"`
	} `json:"totp"`
}

type TenantAssignment

type TenantAssignment struct {
	TenantID   string `json:"tenant_id"`
	TenantName string `json:"tenant_name"`
	TenantSlug string `json:"tenant_slug"`
}

TenantAssignment represents a user's assignment to a tenant

type TenantTokenOptions

type TenantTokenOptions struct {
	TenantID        *string
	TenantRole      string
	IsInstanceAdmin bool
}

TenantTokenOptions contains options for generating tenant-aware tokens

type TokenBlacklistEntry

type TokenBlacklistEntry struct {
	ID        string    `json:"id" db:"id"`
	TokenJTI  string    `json:"token_jti" db:"token_jti"`
	RevokedBy string    `json:"revoked_by" db:"revoked_by"`
	Reason    string    `json:"reason" db:"reason"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
}

TokenBlacklistEntry represents a blacklisted token

type TokenBlacklistRepository

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

TokenBlacklistRepository handles database operations for token blacklist

func NewTokenBlacklistRepository

func NewTokenBlacklistRepository(db *database.Connection) *TokenBlacklistRepository

NewTokenBlacklistRepository creates a new token blacklist repository

func (*TokenBlacklistRepository) Add

func (r *TokenBlacklistRepository) Add(ctx context.Context, jti string, revokedBy *string, reason string, expiresAt time.Time) error

Add adds a token to the blacklist. revokedBy can be nil for tokens without a user.

func (*TokenBlacklistRepository) DeleteByUser

func (r *TokenBlacklistRepository) DeleteByUser(ctx context.Context, userID string) error

DeleteByUser removes all blacklist entries for a user

func (*TokenBlacklistRepository) DeleteExpired

func (r *TokenBlacklistRepository) DeleteExpired(ctx context.Context) (int64, error)

DeleteExpired removes expired tokens from the blacklist

func (*TokenBlacklistRepository) GetByJTI

GetByJTI retrieves a blacklist entry by token JTI

func (*TokenBlacklistRepository) IsBlacklisted

func (r *TokenBlacklistRepository) IsBlacklisted(ctx context.Context, jti string) (bool, error)

IsBlacklisted checks if a token JTI is in the blacklist

func (*TokenBlacklistRepository) RevokeAllUserTokens

func (r *TokenBlacklistRepository) RevokeAllUserTokens(ctx context.Context, userID, reason string, expiry time.Duration) error

RevokeAllUserTokens revokes all tokens for a specific user The expiry parameter determines how long the revocation marker persists

type TokenBlacklistRepositoryInterface

type TokenBlacklistRepositoryInterface interface {
	// Add adds a token to the blacklist
	// jti is the JWT ID from the token claims
	// revokedBy can be nil for tokens without a user (e.g., anonymous or service tokens)
	Add(ctx context.Context, jti string, revokedBy *string, reason string, expiresAt time.Time) error

	// IsBlacklisted checks if a token (by JTI) has been revoked
	IsBlacklisted(ctx context.Context, jti string) (bool, error)

	// GetByJTI retrieves a blacklist entry by JTI
	GetByJTI(ctx context.Context, jti string) (*TokenBlacklistEntry, error)

	// RevokeAllUserTokens blacklists all tokens for a user
	// expiry is the duration for which the revocation marker should persist
	RevokeAllUserTokens(ctx context.Context, userID, reason string, expiry time.Duration) error

	// DeleteExpired removes expired blacklist entries (cleanup job)
	DeleteExpired(ctx context.Context) (int64, error)

	// DeleteByUser removes all blacklist entries for a user
	DeleteByUser(ctx context.Context, userID string) error
}

TokenBlacklistRepositoryInterface defines token blacklist operations. Used to track revoked tokens that haven't yet expired.

type TokenBlacklistService

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

TokenBlacklistService provides token blacklisting/revocation functionality

func NewTokenBlacklistService

func NewTokenBlacklistService(repo *TokenBlacklistRepository, jwtManager *JWTManager) *TokenBlacklistService

NewTokenBlacklistService creates a new token blacklist service

func (*TokenBlacklistService) CleanupExpiredTokens

func (s *TokenBlacklistService) CleanupExpiredTokens(ctx context.Context) (int64, error)

CleanupExpiredTokens removes expired tokens from the blacklist

func (*TokenBlacklistService) IsTokenRevoked

func (s *TokenBlacklistService) IsTokenRevoked(ctx context.Context, jti string, userID string, tokenIssuedAt time.Time) (bool, error)

IsTokenRevoked checks if a token has been revoked It checks both exact JTI revocation and user-wide revocation

func (*TokenBlacklistService) RevokeAllUserTokens

func (s *TokenBlacklistService) RevokeAllUserTokens(ctx context.Context, userID, reason string) error

RevokeAllUserTokens revokes all tokens for a user The revocation marker expires after the maximum token TTL to ensure it covers all valid tokens at the time of revocation

func (*TokenBlacklistService) RevokeToken

func (s *TokenBlacklistService) RevokeToken(ctx context.Context, token, reason string) error

RevokeToken revokes a specific token

type TokenClaims

type TokenClaims struct {
	UserID       string                 `json:"user_id"`
	Email        string                 `json:"email,omitempty"` // Empty for anonymous users
	Name         string                 `json:"name,omitempty"`  // Display name of the user
	Role         string                 `json:"role,omitempty"`
	SessionID    string                 `json:"session_id,omitempty"`    // Empty for anonymous users (no session)
	TokenType    string                 `json:"token_type"`              // "access" or "refresh"
	IsAnonymous  bool                   `json:"is_anonymous,omitempty"`  // True for anonymous users
	UserMetadata any                    `json:"user_metadata,omitempty"` // User-editable metadata
	AppMetadata  any                    `json:"app_metadata,omitempty"`  // Application/admin-only metadata
	RawClaims    map[string]interface{} `json:"-"`                       // Full claims map for RLS (not serialized)
	jwt.RegisteredClaims

	// Multi-tenancy fields
	TenantID        *string `json:"tenant_id,omitempty"`         // Current tenant ID
	TenantRole      string  `json:"tenant_role,omitempty"`       // User's role in current tenant (tenant_admin, tenant_member)
	IsInstanceAdmin bool    `json:"is_instance_admin,omitempty"` // True for instance-level admins

	// Impersonation tracking - for security audit and revocation
	ImpersonatedBy string `json:"impersonated_by,omitempty"` // Admin user ID who issued this impersonation token
}

TokenClaims represents the JWT claims

type TokenOption

type TokenOption func(*tokenOptions)

TokenOption is a functional option for token generation

func WithImpersonatedBy

func WithImpersonatedBy(adminID string) TokenOption

WithImpersonatedBy sets the admin user ID who is impersonating

func WithTenantContext

func WithTenantContext(tenantID, tenantRole string, isInstanceAdmin bool) TokenOption

WithTenantContext sets tenant context for the generated token

type TrustRequest

type TrustRequest struct {
	UserID            *uuid.UUID
	Email             string
	IPAddress         string
	DeviceFingerprint string
	UserAgent         string
	TrustToken        string // Previously issued trust token
}

TrustRequest contains information for trust evaluation

type TrustResult

type TrustResult struct {
	TotalScore      int           `json:"trust_score"`
	Signals         []TrustSignal `json:"signals,omitempty"`
	CaptchaRequired bool          `json:"captcha_required"`
	Reason          string        `json:"reason"`
}

TrustResult contains the complete trust evaluation

type TrustSignal

type TrustSignal struct {
	Name   string `json:"name"`
	Score  int    `json:"score"`
	Reason string `json:"reason"`
}

TrustSignal represents a single factor in trust calculation

type TurnstileProvider

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

TurnstileProvider implements CAPTCHA verification using Cloudflare Turnstile

func NewTurnstileProvider

func NewTurnstileProvider(secretKey string, httpClient *http.Client) *TurnstileProvider

NewTurnstileProvider creates a new Cloudflare Turnstile provider

func (*TurnstileProvider) Name

func (p *TurnstileProvider) Name() string

Name returns the provider name

func (*TurnstileProvider) Verify

func (p *TurnstileProvider) Verify(ctx context.Context, token string, remoteIP string) (*CaptchaResult, error)

Verify validates a Cloudflare Turnstile response token

type UpdateAdminUserRequest

type UpdateAdminUserRequest struct {
	Email        *string                `json:"email,omitempty"`
	Role         *string                `json:"role,omitempty"`
	Password     *string                `json:"password,omitempty"`
	UserMetadata map[string]interface{} `json:"user_metadata,omitempty"`
}

UpdateUserRequest for admin user updates

type UpdateUserRequest

type UpdateUserRequest struct {
	Email         *string `json:"email,omitempty"`
	EmailVerified *bool   `json:"email_verified,omitempty"`
	Role          *string `json:"role,omitempty"`
	UserMetadata  any     `json:"user_metadata,omitempty"` // User-editable metadata
	AppMetadata   any     `json:"app_metadata,omitempty"`  // Application/admin-only metadata (admin only)
}

UpdateUserRequest represents a request to update a user

type User

type User struct {
	ID                  string     `json:"id" db:"id"`
	Email               string     `json:"email" db:"email"`
	PasswordHash        string     `json:"-" db:"password_hash"`
	EmailVerified       bool       `json:"email_verified" db:"email_verified"`
	Role                string     `json:"role,omitempty" db:"role"`
	TenantID            string     `json:"tenant_id,omitempty" db:"tenant_id"`
	UserMetadata        any        `json:"user_metadata,omitempty" db:"user_metadata"`
	AppMetadata         any        `json:"app_metadata,omitempty" db:"app_metadata"`
	FailedLoginAttempts int        `json:"-" db:"failed_login_attempts"`
	IsLocked            bool       `json:"-" db:"is_locked"`
	LockedUntil         *time.Time `json:"-" db:"locked_until"`
	CreatedAt           time.Time  `json:"created_at" db:"created_at"`
	UpdatedAt           time.Time  `json:"updated_at" db:"updated_at"`
}

User represents a user in the system

type UserIdentity

type UserIdentity struct {
	ID             string                 `json:"id" db:"id"`
	UserID         string                 `json:"user_id" db:"user_id"`
	Provider       string                 `json:"provider" db:"provider"`
	ProviderUserID string                 `json:"provider_user_id" db:"provider_user_id"`
	Email          *string                `json:"email,omitempty" db:"email"`
	IdentityData   map[string]interface{} `json:"identity_data,omitempty" db:"metadata"`
	CreatedAt      time.Time              `json:"created_at" db:"created_at"`
	UpdatedAt      time.Time              `json:"updated_at" db:"updated_at"`
}

UserIdentity represents a linked OAuth identity

type UserManagementService

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

UserManagementService provides admin operations for user management

func NewUserManagementService

func NewUserManagementService(
	userRepo *UserRepository,
	sessionRepo *SessionRepository,
	passwordHasher *PasswordHasher,
	emailService EmailService,
	baseURL string,
) *UserManagementService

NewUserManagementService creates a new user management service

func (*UserManagementService) DeleteUser

func (s *UserManagementService) DeleteUser(ctx context.Context, userID string, userType string) error

DeleteUser deletes a user (cascades to sessions, tokens, etc.)

func (*UserManagementService) GetEnrichedUserByID

func (s *UserManagementService) GetEnrichedUserByID(ctx context.Context, userID string, userType string) (*EnrichedUser, error)

GetEnrichedUserByID returns a single user with enriched metadata userType can be "app" for auth.users or "platform" for platform.users

func (*UserManagementService) InviteUser

InviteUser creates a new user and either sends them an invite email or returns a temp password

func (*UserManagementService) ListEnrichedUsers

func (s *UserManagementService) ListEnrichedUsers(ctx context.Context, userType string, tenantID string) ([]*EnrichedUser, error)

ListEnrichedUsers returns a list of users with enriched metadata userType can be "app" for auth.users or "platform" for platform.users tenantID is optional and filters app users by tenant membership

func (*UserManagementService) LockUser

func (s *UserManagementService) LockUser(ctx context.Context, userID string, userType string) error

LockUser locks a user account

func (*UserManagementService) ResetUserPassword

func (s *UserManagementService) ResetUserPassword(ctx context.Context, userID string, userType string) (string, error)

ResetUserPassword triggers a password reset for a user

func (*UserManagementService) UnlockUser

func (s *UserManagementService) UnlockUser(ctx context.Context, userID string, userType string) error

UnlockUser unlocks a user account

func (*UserManagementService) UpdateUser

func (s *UserManagementService) UpdateUser(ctx context.Context, userID string, req UpdateAdminUserRequest, userType string) (*EnrichedUser, error)

UpdateUser updates a user's information

func (*UserManagementService) UpdateUserRole

func (s *UserManagementService) UpdateUserRole(ctx context.Context, userID string, newRole string, userType string) (*User, error)

UpdateUserRole updates a user's role

type UserRepository

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

UserRepository handles database operations for users

func NewUserRepository

func NewUserRepository(db *database.Connection) *UserRepository

NewUserRepository creates a new user repository

func (*UserRepository) Count

func (r *UserRepository) Count(ctx context.Context) (int, error)

Count returns the total number of users

func (*UserRepository) Create

func (r *UserRepository) Create(ctx context.Context, req CreateUserRequest, passwordHash string) (*User, error)

Create creates a new user

func (*UserRepository) CreateInTable

func (r *UserRepository) CreateInTable(ctx context.Context, req CreateUserRequest, passwordHash string, userType string) (*User, error)

CreateInTable creates a new user in the specified table (auth.users or platform.users)

func (*UserRepository) Delete

func (r *UserRepository) Delete(ctx context.Context, id string) error

Delete deletes a user

func (*UserRepository) DeleteFromTable

func (r *UserRepository) DeleteFromTable(ctx context.Context, id string, userType string) error

DeleteFromTable deletes a user from the specified table

func (*UserRepository) GetByEmail

func (r *UserRepository) GetByEmail(ctx context.Context, email string) (*User, error)

GetByEmail retrieves a user by email

func (*UserRepository) GetByID

func (r *UserRepository) GetByID(ctx context.Context, id string) (*User, error)

GetByID retrieves a user by ID

func (*UserRepository) GetByIDFromTable

func (r *UserRepository) GetByIDFromTable(ctx context.Context, id string, userType string) (*User, error)

GetByIDFromTable retrieves a user by ID from the specified table

func (*UserRepository) IncrementFailedLoginAttempts

func (r *UserRepository) IncrementFailedLoginAttempts(ctx context.Context, userID string) error

IncrementFailedLoginAttempts increments failed login attempts and locks account after threshold SECURITY FIX: Now sets locked_until to allow automatic unlock after 15 minutes

func (*UserRepository) List

func (r *UserRepository) List(ctx context.Context, limit, offset int) ([]*User, error)

List retrieves users with pagination

func (*UserRepository) ResetFailedLoginAttempts

func (r *UserRepository) ResetFailedLoginAttempts(ctx context.Context, userID string) error

ResetFailedLoginAttempts resets failed login attempts after successful login

func (*UserRepository) UnlockUser

func (r *UserRepository) UnlockUser(ctx context.Context, userID string) error

UnlockUser unlocks a user account (admin operation)

func (*UserRepository) Update

func (r *UserRepository) Update(ctx context.Context, id string, req UpdateUserRequest) (*User, error)

Update updates a user

func (*UserRepository) UpdateInTable

func (r *UserRepository) UpdateInTable(ctx context.Context, id string, req UpdateUserRequest, userType string) (*User, error)

UpdateInTable updates a user in the specified table

func (*UserRepository) UpdatePassword

func (r *UserRepository) UpdatePassword(ctx context.Context, id string, newPasswordHash string) error

UpdatePassword updates a user's password

func (*UserRepository) UpdatePasswordInTable

func (r *UserRepository) UpdatePasswordInTable(ctx context.Context, id string, newPasswordHash string, userType string) error

UpdatePasswordInTable updates a user's password in the specified table

func (*UserRepository) VerifyEmail

func (r *UserRepository) VerifyEmail(ctx context.Context, id string) error

VerifyEmail marks a user's email as verified

type UserRepositoryInterface

type UserRepositoryInterface interface {
	// Create creates a new user with the given details
	Create(ctx context.Context, req CreateUserRequest, passwordHash string) (*User, error)

	// GetByID retrieves a user by their ID
	GetByID(ctx context.Context, id string) (*User, error)

	// GetByEmail retrieves a user by their email address
	GetByEmail(ctx context.Context, email string) (*User, error)

	// List returns a paginated list of users
	List(ctx context.Context, limit, offset int) ([]*User, error)

	// Update updates a user's details
	Update(ctx context.Context, id string, req UpdateUserRequest) (*User, error)

	// UpdatePassword updates a user's password hash
	UpdatePassword(ctx context.Context, id string, newPasswordHash string) error

	// VerifyEmail marks a user's email as verified
	VerifyEmail(ctx context.Context, id string) error

	// IncrementFailedLoginAttempts increments the failed login counter
	IncrementFailedLoginAttempts(ctx context.Context, userID string) error

	// ResetFailedLoginAttempts resets the failed login counter
	ResetFailedLoginAttempts(ctx context.Context, userID string) error

	// UnlockUser unlocks a locked user account
	UnlockUser(ctx context.Context, userID string) error

	// Delete removes a user by their ID
	Delete(ctx context.Context, id string) error

	// Count returns the total number of users
	Count(ctx context.Context) (int, error)
}

UserRepositoryInterface defines user data operations. Implementations can be backed by a real database or mocks for testing. Note: All IDs are strings (UUID strings) to match existing implementation.

type UserTrustSignal

type UserTrustSignal struct {
	ID                string
	UserID            uuid.UUID
	IPAddress         string
	DeviceFingerprint string
	UserAgent         string
	FirstSeenAt       time.Time
	LastSeenAt        time.Time
	SuccessfulLogins  int
	FailedAttempts    int
	LastCaptchaAt     *time.Time
	IsTrusted         bool
	IsBlocked         bool
}

UserTrustSignal represents a stored trust signal for a user

type UserUpdateValidator

type UserUpdateValidator struct{}

UserUpdateValidator validates user update operations

func (*UserUpdateValidator) ValidateUpdate

func (v *UserUpdateValidator) ValidateUpdate(req UpdateUserRequest) error

ValidateUpdate validates user update request

type ValidationError

type ValidationError struct {
	Field   string
	Message string
}

ValidationError wraps multiple validation errors

func NewValidationError

func NewValidationError(field string, err error) *ValidationError

NewValidationError creates a new validation error

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

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