errs

package
v0.0.10 Latest Latest
Warning

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

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

README

Authsome Error Package

A robust, production-ready error handling system for Authsome that builds on Forge's error infrastructure.

Overview

The internal/errs package provides a comprehensive error type system designed for authentication and authorization systems. It offers:

  • Structured Errors: Rich error context with codes, HTTP status, and metadata
  • Error Wrapping: Full support for Go 1.13+ error wrapping with errors.Is and errors.As
  • Forge Integration: Seamless conversion to Forge's HTTPError for handler responses
  • Distributed Tracing: Built-in trace ID support for request correlation
  • Type Safety: Strongly-typed error constructors for common scenarios
  • JSON Serialization: Ready for API responses with proper JSON tags

Core Type: AuthsomeError

type AuthsomeError struct {
    Code       string         // Error code (e.g., "USER_NOT_FOUND")
    Message    string         // Human-readable message
    HTTPStatus int            // HTTP status code
    Err        error          // Underlying error (if any)
    Context    map[string]any // Additional debug context
    Timestamp  time.Time      // When the error occurred
    TraceID    string         // Distributed tracing ID
    Details    any            // Structured details (e.g., validation errors)
}

Quick Start

Basic Usage
import "github.com/xraph/authsome/internal/errs"

// Simple error creation
err := errs.UserNotFound()
// Returns: USER_NOT_FOUND: User not found (404)

// With additional context
err := errs.EmailAlreadyExists("user@example.com")
// Returns: EMAIL_ALREADY_EXISTS: Email address already registered (409)
// Context: {"email": "user@example.com"}
Error Wrapping
// Wrap an underlying error
dbErr := errors.New("connection timeout")
err := errs.DatabaseError("SELECT users", dbErr)

// Can still find the original error
if errors.Is(err, dbErr) {
    // Handle database connection issue
}
Adding Context
err := errs.PermissionDenied("delete", "user:123").
    WithContext("user_role", "viewer").
    WithContext("required_role", "admin").
    WithTraceID(requestID)

// Context: {"action": "delete", "resource": "user:123", 
//           "user_role": "viewer", "required_role": "admin"}
Handler Integration
func (h *Handler) GetUser(c forge.Context) error {
    user, err := h.service.FindByID(ctx, userID)
    if err != nil {
        var authErr *errs.AuthsomeError
        if errors.As(err, &authErr) {
            // Convert to Forge HTTPError for automatic response handling
            return authErr.ToHTTPError()
        }
        return err
    }
    
    return c.JSON(200, user)
}

Error Categories

Authentication Errors (401, 403)
errs.InvalidCredentials()              // Invalid email or password
errs.EmailNotVerified(email)           // Email not verified
errs.AccountLocked(reason)             // Account locked (basic)
errs.AccountLockedWithTime(reason, time) // Account locked with duration info
errs.TwoFactorRequired()               // 2FA required
errs.TokenExpired()                    // Token expired
errs.InvalidOTP()                      // Invalid OTP code
User Errors (400, 404, 409)
errs.UserNotFound()                    // User not found
errs.EmailAlreadyExists(email)         // Email already registered
errs.UsernameAlreadyExists(username)   // Username taken
errs.WeakPassword(reason)              // Password doesn't meet requirements
Session Errors (401, 409)
errs.SessionNotFound()                 // Session not found
errs.SessionExpired()                  // Session expired
errs.SessionRevoked()                  // Session revoked
errs.ConcurrentSessionLimit()          // Too many active sessions
Organization Errors (403, 404, 409)
errs.OrganizationNotFound()            // Organization not found
errs.NotMember()                       // Not an organization member
errs.InsufficientRole(required)        // Insufficient role
errs.SlugAlreadyExists(slug)           // Slug already in use
RBAC Errors (403, 404)
errs.PermissionDenied(action, resource) // Permission denied
errs.RoleNotFound(role)                 // Role not found
errs.PolicyViolation(policy, reason)    // Policy violation
Rate Limiting Errors (429)
errs.RateLimitExceeded(retryAfter)     // Rate limit exceeded
errs.TooManyAttempts(retryAfter)       // Too many failed attempts
Validation Errors (400)
fields := map[string]string{
    "email": "invalid format",
    "password": "too short",
}
errs.ValidationFailed(fields)          // Multiple validation errors

errs.InvalidInput(field, reason)       // Invalid input
errs.RequiredField(field)              // Required field missing
Plugin Errors (404, 500, 503)
errs.PluginNotFound(pluginID)          // Plugin not found
errs.PluginInitFailed(pluginID, err)   // Plugin init failed
errs.PluginDisabled(pluginID)          // Plugin disabled
OAuth/SSO Errors (400, 502)
errs.OAuthFailed(provider, reason)     // OAuth failed
errs.InvalidOAuthState()               // Invalid state parameter
errs.SAMLError(reason)                 // SAML error
General Errors (500, 501)
errs.InternalError(err)                // Internal server error
errs.DatabaseError(operation, err)     // Database error
errs.NotImplemented(feature)           // Feature not implemented

Advanced Usage

Error Comparison with Sentinel Errors
err := someFunction()

// Using errors.Is for code-based comparison
if errs.Is(err, errs.ErrUserNotFound) {
    // Handle user not found
}

// Using errors.As to extract AuthsomeError
var authErr *errs.AuthsomeError
if errors.As(err, &authErr) {
    log.Printf("Error code: %s, Status: %d", authErr.Code, authErr.HTTPStatus)
}
Creating Custom Errors
// Use New for custom errors
err := errs.New(
    "CUSTOM_ERROR_CODE",
    "Something specific happened",
    http.StatusBadRequest,
).WithContext("custom_field", "value")

// Or wrap existing errors
err := errs.Wrap(
    originalErr,
    "CUSTOM_ERROR_CODE",
    "Custom message",
    http.StatusInternalServerError,
)
Helper Functions
// Extract HTTP status code from any error
status := errs.GetHTTPStatus(err)  // Returns 500 if not found

// Extract error code
code := errs.GetErrorCode(err)     // Returns "INTERNAL_ERROR" if not found

// Check if error is specific type
if errs.GetErrorCode(err) == errs.CodeUserNotFound {
    // Handle user not found
}
Validation Error Details
validationErrors := map[string]string{
    "email":    "Invalid email format",
    "password": "Password must be at least 8 characters",
    "name":     "Name is required",
}

err := errs.ValidationFailed(validationErrors)

// In handler
return c.JSON(err.HTTPStatus, map[string]interface{}{
    "error":   err.Code,
    "message": err.Message,
    "details": err.Details, // Contains the validation errors map
})

Best Practices

1. Use Specific Error Constructors

Good:

return errs.EmailAlreadyExists(email)

Avoid:

return errs.New("EMAIL_ALREADY_EXISTS", "Email exists", 409)
2. Always Add Context
// Good - includes relevant context
return errs.PermissionDenied("delete", "user:"+userID).
    WithContext("actor_role", actorRole).
    WithTraceID(requestID)

// Less helpful
return errs.PermissionDenied("delete", "user")
3. Wrap Underlying Errors
// Good - preserves error chain
user, err := repo.FindByID(ctx, id)
if err != nil {
    return errs.DatabaseError("FindByID", err)
}

// Bad - loses original error
user, err := repo.FindByID(ctx, id)
if err != nil {
    return errs.InternalError(nil)
}
4. Use Sentinel Errors for Comparison
// Good - uses sentinel
if errors.Is(err, errs.ErrUserNotFound) {
    // Handle
}

// Avoid - string comparison
if err.Error() == "user not found" {
    // Fragile
}
5. Convert to HTTPError in Handlers
func (h *Handler) DoSomething(c forge.Context) error {
    result, err := h.service.Process(ctx)
    if err != nil {
        // Check if it's an AuthsomeError
        var authErr *errs.AuthsomeError
        if errors.As(err, &authErr) {
            // Let Forge handle the HTTP response
            return authErr.ToHTTPError()
        }
        // Fallback for unknown errors
        return forge.InternalError(err)
    }
    return c.JSON(200, result)
}

Error Codes Reference

All error codes are constants in the package:

  • CodeInvalidCredentials - Invalid authentication credentials
  • CodeUserNotFound - User does not exist
  • CodeSessionExpired - Session has expired
  • CodePermissionDenied - Permission denied for action
  • CodeRateLimitExceeded - Rate limit exceeded
  • ...and 50+ more

See errors.go for the complete list.

JSON Response Format

When serialized to JSON, AuthsomeError produces:

{
  "code": "USER_NOT_FOUND",
  "message": "User not found",
  "timestamp": "2024-01-15T10:30:00Z",
  "trace_id": "req-123-abc",
  "context": {
    "user_id": "usr_abc123"
  },
  "details": null
}

Note: Err and HTTPStatus fields are omitted from JSON (marked with json:"-").

Integration with Existing Code

Migrating from types.Errors

The package provides sentinel errors that match the existing types package:

// Old code using types
import "github.com/xraph/authsome/types"

if err == types.ErrUserNotFound {
    // Handle
}

// New code using errs
import "github.com/xraph/authsome/internal/errs"

if errors.Is(err, errs.ErrUserNotFound) {
    // Handle - uses proper error comparison
}
Service Layer Pattern
// In service
func (s *Service) CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error) {
    // Check if user exists
    existing, _ := s.repo.FindByEmail(ctx, req.Email)
    if existing != nil {
        return nil, errs.EmailAlreadyExists(req.Email)
    }
    
    // Validate password
    if !isStrongPassword(req.Password) {
        return nil, errs.WeakPassword("must contain uppercase, lowercase, and number")
    }
    
    // Create user
    user, err := s.repo.Create(ctx, req)
    if err != nil {
        return nil, errs.DatabaseError("Create", err).
            WithContext("email", req.Email)
    }
    
    return user, nil
}

Testing

The package includes comprehensive tests. To run:

go test -v ./internal/errs/

All 40+ test cases cover:

  • Error creation and wrapping
  • Error comparison with errors.Is
  • Error extraction with errors.As
  • Context and detail handling
  • Conversion methods
  • Sentinel error behavior
  • Error chaining

Performance Considerations

  • Context maps are pre-allocated but start small
  • Timestamps use time.Now() which is fast
  • Error constructors are lightweight
  • No reflection or heavy allocations
  • Suitable for high-throughput APIs

Thread Safety

AuthsomeError is not thread-safe for mutation. Once created and configured (using WithContext, etc.), treat it as immutable.

For concurrent operations, create errors independently per goroutine.

Documentation

Overview

Example (Basic)

Example_basic demonstrates basic error creation and usage.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.UserNotFound()
	fmt.Println(err.Error())
	fmt.Println(err.Code)
	fmt.Println(err.HTTPStatus)

}
Output:

USER_NOT_FOUND: User not found
USER_NOT_FOUND
404
Example (CustomError)

Example_customError demonstrates creating custom errors.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.New(
		"CUSTOM_BUSINESS_RULE",
		"Cannot perform action during maintenance window",
		503,
	).WithContext("maintenance_until", "2024-01-15T18:00:00Z").
		WithContext("feature", "user_registration")

	fmt.Println(err.Code)
	fmt.Println(err.Message)
	fmt.Println(err.HTTPStatus)

}
Output:

CUSTOM_BUSINESS_RULE
Cannot perform action during maintenance window
503
Example (ErrorChaining)

Example_errorChaining demonstrates error chain navigation.

package main

import (
	"errors"
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	// Create a chain of errors
	originalErr := errors.New("network timeout")
	dbErr := errs.DatabaseError("query", originalErr)
	serviceErr := fmt.Errorf("failed to fetch user: %w", dbErr)

	// Can still find original error in the chain
	fmt.Println(errors.Is(serviceErr, originalErr))

	// Extract the AuthsomeError
	var authErr *errs.AuthsomeError
	if errors.As(serviceErr, &authErr) {
		fmt.Printf("Code: %s\n", authErr.Code)
		fmt.Printf("Has underlying error: %v\n", authErr.Err != nil)
	}

}
Output:

true
Code: DATABASE_ERROR
Has underlying error: true
Example (Extraction)

Example_extraction demonstrates extracting AuthsomeError details.

package main

import (
	"errors"
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.PermissionDenied("delete", "user:123")

	// Extract the AuthsomeError
	var authErr *errs.AuthsomeError
	if errors.As(err, &authErr) {
		fmt.Printf("Code: %s\n", authErr.Code)
		fmt.Printf("Status: %d\n", authErr.HTTPStatus)
		fmt.Printf("Action: %s\n", authErr.Context["action"])
	}

}
Output:

Code: PERMISSION_DENIED
Status: 403
Action: delete
Example (Helpers)

Example_helpers demonstrates helper functions.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.UserNotFound()

	// Extract HTTP status
	status := errs.GetHTTPStatus(err)
	fmt.Printf("HTTP Status: %d\n", status)

	// Extract error code
	code := errs.GetErrorCode(err)
	fmt.Printf("Error Code: %s\n", code)

}
Output:

HTTP Status: 404
Error Code: USER_NOT_FOUND
Example (MultipleContexts)

Example_multipleContexts demonstrates building rich error context.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.PermissionDenied("update", "organization:123").
		WithContext("user_id", "usr_456").
		WithContext("user_role", "viewer").
		WithContext("required_role", "admin").
		WithContext("ip_address", "192.168.1.100").
		WithTraceID("trace-789")

	fmt.Printf("Action denied: %s on %s\n",
		err.Context["action"],
		err.Context["resource"])
	fmt.Printf("User %s (role: %s) needs role: %s\n",
		err.Context["user_id"],
		err.Context["user_role"],
		err.Context["required_role"])

}
Output:

Action denied: update on organization:123
User usr_456 (role: viewer) needs role: admin
Example (Oauth)

Example_oauth demonstrates OAuth error handling.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.OAuthFailed("google", "invalid state parameter").
		WithContext("client_id", "client_123").
		WithContext("redirect_uri", "https://app.example.com/callback")

	fmt.Println(err.Code)
	fmt.Println(err.Message)
	fmt.Printf("Provider: %s\n", err.Context["provider"])
	fmt.Printf("Reason: %s\n", err.Context["reason"])

}
Output:

OAUTH_FAILED
OAuth authentication failed
Provider: google
Reason: invalid state parameter
Example (RateLimiting)

Example_rateLimiting demonstrates rate limiting errors.

package main

import (
	"fmt"
	"time"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	retryAfter := 60 * time.Second
	err := errs.RateLimitExceeded(retryAfter)

	fmt.Println(err.Code)
	fmt.Println(err.HTTPStatus)
	fmt.Printf("Retry after: %.0f seconds\n", err.Context["retry_after"])

}
Output:

RATE_LIMIT_EXCEEDED
429
Retry after: 60 seconds
Example (SentinelComparison)

Example_sentinelComparison demonstrates using sentinel errors.

package main

import (
	"errors"
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.UserNotFound()

	// Use errors.Is for comparison
	if errors.Is(err, errs.ErrUserNotFound) {
		fmt.Println("User not found!")
	}

}
Output:

User not found!
Example (Service)

Example_service demonstrates typical service layer usage.

package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	// Simulate a service method
	createUser := func(ctx context.Context, email string) error {
		// Check if user exists (simulated)
		userExists := true
		if userExists {
			return errs.EmailAlreadyExists(email).
				WithContext("source", "registration").
				WithTraceID("req-abc-123")
		}

		return nil
	}

	err := createUser(context.Background(), "existing@example.com")
	if err != nil {
		var authErr *errs.AuthsomeError
		if errors.As(err, &authErr) {
			fmt.Printf("Error: %s\n", authErr.Message)
			fmt.Printf("Email: %s\n", authErr.Context["email"])
			fmt.Printf("Source: %s\n", authErr.Context["source"])
		}
	}

}
Output:

Error: Email address already registered
Email: existing@example.com
Source: registration
Example (ValidationErrors)

Example_validationErrors demonstrates validation error handling.

package main

import (
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	validationErrors := map[string]string{
		"email":    "invalid format",
		"password": "too short",
	}

	err := errs.ValidationFailed(validationErrors)

	fmt.Println(err.Code)
	fmt.Println(err.HTTPStatus)

	if details, ok := err.Details.(map[string]string); ok {
		fmt.Printf("Validation errors: %d\n", len(details))
	}

}
Output:

VALIDATION_FAILED
400
Validation errors: 2
Example (WithContext)

Example_withContext demonstrates adding context to errors.

package main

import (
	"fmt"
	"time"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	err := errs.EmailAlreadyExists("user@example.com").
		WithContext("attempted_at", time.Now().Format(time.RFC3339)).
		WithTraceID("trace-123")

	fmt.Println(err.Code)
	fmt.Println(err.Context["email"])
	fmt.Println(err.TraceID)

}
Output:

EMAIL_ALREADY_EXISTS
user@example.com
trace-123
Example (Wrapping)

Example_wrapping demonstrates error wrapping.

package main

import (
	"errors"
	"fmt"

	"github.com/xraph/authsome/internal/errs"
)

func main() {
	dbErr := errors.New("connection timeout")
	err := errs.DatabaseError("SELECT", dbErr)

	fmt.Println(err.Code)
	fmt.Println(errors.Is(err, dbErr)) // Can still find original error

}
Output:

DATABASE_ERROR
true

Index

Examples

Constants

View Source
const (
	// Authentication errors
	CodeInvalidCredentials = "INVALID_CREDENTIALS"
	CodeEmailNotVerified   = "EMAIL_NOT_VERIFIED"
	CodeAccountLocked      = "ACCOUNT_LOCKED"
	CodeAccountDisabled    = "ACCOUNT_DISABLED"
	CodePasswordExpired    = "PASSWORD_EXPIRED"
	CodeTwoFactorRequired  = "TWO_FACTOR_REQUIRED"
	CodeStepUpRequired     = "STEP_UP_REQUIRED"
	CodeInvalidToken       = "INVALID_TOKEN"
	CodeTokenExpired       = "TOKEN_EXPIRED"
	CodeInvalidOTP         = "INVALID_OTP"
	CodeOTPExpired         = "OTP_EXPIRED"
	CodeMagicLinkExpired   = "MAGIC_LINK_EXPIRED"
	CodeMagicLinkInvalid   = "MAGIC_LINK_INVALID"

	// User errors
	CodeUserNotFound          = "USER_NOT_FOUND"
	CodeUserAlreadyExists     = "USER_ALREADY_EXISTS"
	CodeEmailAlreadyExists    = "EMAIL_ALREADY_EXISTS"
	CodeUsernameAlreadyExists = "USERNAME_ALREADY_EXISTS"
	CodePhoneAlreadyExists    = "PHONE_ALREADY_EXISTS"
	CodeInvalidEmail          = "INVALID_EMAIL"
	CodeInvalidPhone          = "INVALID_PHONE"
	CodeInvalidUsername       = "INVALID_USERNAME"
	CodeWeakPassword          = "WEAK_PASSWORD"

	// Session errors
	CodeSessionNotFound        = "SESSION_NOT_FOUND"
	CodeSessionExpired         = "SESSION_EXPIRED"
	CodeSessionInvalid         = "SESSION_INVALID"
	CodeSessionRevoked         = "SESSION_REVOKED"
	CodeConcurrentSessionLimit = "CONCURRENT_SESSION_LIMIT"
	CodeSessionConflict        = "SESSION_CONFLICT"

	// Organization errors
	CodeOrganizationNotFound     = "ORGANIZATION_NOT_FOUND"
	CodeOrganizationExists       = "ORGANIZATION_EXISTS"
	CodeNotMember                = "NOT_ORGANIZATION_MEMBER"
	CodeInsufficientRole         = "INSUFFICIENT_ROLE"
	CodeInvalidSlug              = "INVALID_SLUG"
	CodeSlugAlreadyExists        = "SLUG_ALREADY_EXISTS"
	CodeOrganizationLimitReached = "ORGANIZATION_LIMIT_REACHED"

	// Team errors
	CodeTeamNotFound      = "TEAM_NOT_FOUND"
	CodeTeamAlreadyExists = "TEAM_ALREADY_EXISTS"
	CodeNotTeamMember     = "NOT_TEAM_MEMBER"

	// Invitation errors
	CodeInvitationNotFound  = "INVITATION_NOT_FOUND"
	CodeInvitationExpired   = "INVITATION_EXPIRED"
	CodeInvitationAccepted  = "INVITATION_ACCEPTED"
	CodeInvitationCancelled = "INVITATION_CANCELLED"

	// RBAC errors
	CodePermissionDenied  = "PERMISSION_DENIED"
	CodeRoleNotFound      = "ROLE_NOT_FOUND"
	CodeRoleAlreadyExists = "ROLE_ALREADY_EXISTS"
	CodePolicyViolation   = "POLICY_VIOLATION"
	CodeInvalidPolicy     = "INVALID_POLICY"

	// Rate limiting
	CodeRateLimitExceeded = "RATE_LIMIT_EXCEEDED"
	CodeTooManyAttempts   = "TOO_MANY_ATTEMPTS"

	// Validation errors
	CodeValidationFailed = "VALIDATION_FAILED"
	CodeInvalidInput     = "INVALID_INPUT"
	CodeRequiredField    = "REQUIRED_FIELD"
	CodeInvalidFormat    = "INVALID_FORMAT"

	// Plugin errors
	CodePluginNotFound   = "PLUGIN_NOT_FOUND"
	CodePluginInitFailed = "PLUGIN_INIT_FAILED"
	CodePluginDisabled   = "PLUGIN_DISABLED"

	// OAuth/SSO errors
	CodeOAuthFailed        = "OAUTH_FAILED"
	CodeInvalidOAuthState  = "INVALID_OAUTH_STATE"
	CodeOAuthProviderError = "OAUTH_PROVIDER_ERROR"
	CodeSAMLError          = "SAML_ERROR"
	CodeOIDCError          = "OIDC_ERROR"

	// API Key errors
	CodeAPIKeyNotFound = "API_KEY_NOT_FOUND"
	CodeAPIKeyExpired  = "API_KEY_EXPIRED"
	CodeAPIKeyRevoked  = "API_KEY_REVOKED"
	CodeAPIKeyInvalid  = "API_KEY_INVALID"

	// Webhook errors
	CodeWebhookNotFound       = "WEBHOOK_NOT_FOUND"
	CodeWebhookDeliveryFailed = "WEBHOOK_DELIVERY_FAILED"

	// Notification errors
	CodeNotificationFailed   = "NOTIFICATION_FAILED"
	CodeTemplateNotFound     = "TEMPLATE_NOT_FOUND"
	CodeTemplateRenderFailed = "TEMPLATE_RENDER_FAILED"

	// Device errors
	CodeDeviceNotFound   = "DEVICE_NOT_FOUND"
	CodeDeviceNotTrusted = "DEVICE_NOT_TRUSTED"
	CodeDeviceBlocked    = "DEVICE_BLOCKED"

	// Passkey errors
	CodePasskeyNotFound           = "PASSKEY_NOT_FOUND"
	CodePasskeyVerificationFailed = "PASSKEY_VERIFICATION_FAILED"
	CodePasskeyRegistrationFailed = "PASSKEY_REGISTRATION_FAILED"

	// Compliance errors
	CodeComplianceViolation    = "COMPLIANCE_VIOLATION"
	CodeDataRetentionViolation = "DATA_RETENTION_VIOLATION"

	// SCIM errors
	CodeSCIMResourceNotFound = "SCIM_RESOURCE_NOT_FOUND"
	CodeSCIMInvalidFilter    = "SCIM_INVALID_FILTER"
	CodeSCIMInvalidPath      = "SCIM_INVALID_PATH"

	// General errors
	CodeInternalError  = "INTERNAL_ERROR"
	CodeNotImplemented = "NOT_IMPLEMENTED"
	CodeDatabaseError  = "DATABASE_ERROR"
	CodeCacheError     = "CACHE_ERROR"
	CodeConfigError    = "CONFIG_ERROR"
	CodeBadRequest     = "BAD_REQUEST"
	CodeNotFound       = "NOT_FOUND"
	CodeUnauthorized   = "UNAUTHORIZED"
	CodeConflict       = "CONFLICT"
)

Authsome-specific error codes for structured error handling.

Variables

View Source
var (
	ErrInvalidCredentials   = &AuthsomeError{Code: CodeInvalidCredentials}
	ErrEmailNotVerified     = &AuthsomeError{Code: CodeEmailNotVerified}
	ErrAccountLocked        = &AuthsomeError{Code: CodeAccountLocked}
	ErrUserNotFound         = &AuthsomeError{Code: CodeUserNotFound}
	ErrUserAlreadyExists    = &AuthsomeError{Code: CodeUserAlreadyExists}
	ErrEmailAlreadyExists   = &AuthsomeError{Code: CodeEmailAlreadyExists}
	ErrSessionNotFound      = &AuthsomeError{Code: CodeSessionNotFound}
	ErrSessionExpired       = &AuthsomeError{Code: CodeSessionExpired}
	ErrOrganizationNotFound = &AuthsomeError{Code: CodeOrganizationNotFound}
	ErrPermissionDenied     = &AuthsomeError{Code: CodePermissionDenied}
	ErrRateLimitExceeded    = &AuthsomeError{Code: CodeRateLimitExceeded}
	ErrValidationFailed     = &AuthsomeError{Code: CodeValidationFailed}
	ErrPluginNotFound       = &AuthsomeError{Code: CodePluginNotFound}
	ErrInternalError        = &AuthsomeError{Code: CodeInternalError}
)

Sentinel errors for common cases (no message, just for comparison).

Functions

func As

func As(err error, target any) bool

As finds the first error in err's chain that matches target type.

func GetErrorCode

func GetErrorCode(err error) string

GetErrorCode extracts error code from AuthsomeError, returns CodeInternalError if not found.

func GetHTTPStatus

func GetHTTPStatus(err error) int

GetHTTPStatus extracts HTTP status code from error, returns 500 if not found.

func Is

func Is(err, target error) bool

Is checks if an error matches the target AuthsomeError by code.

Types

type AuthsomeError

type AuthsomeError struct {
	// Code is the authsome error code (e.g., "USER_NOT_FOUND")
	Code string `json:"code"`

	// Message is the human-readable error message
	Message string `json:"message"`

	// HTTPStatus is the HTTP status code to return
	HTTPStatus int `json:"-"`

	// Err is the underlying error (if any)
	Err error `json:"-"`

	// Context provides additional debug information
	Context map[string]any `json:"context,omitempty"`

	// Timestamp is when the error occurred
	Timestamp time.Time `json:"timestamp"`

	// TraceID for distributed tracing (optional)
	TraceID string `json:"trace_id,omitempty"`

	// Details for additional structured information
	Details any `json:"details,omitempty"`
}

AuthsomeError represents an authsome-specific error with rich context. It embeds forge.HTTPError and adds authsome-specific fields.

func APIKeyExpired

func APIKeyExpired() *AuthsomeError

func APIKeyInvalid

func APIKeyInvalid() *AuthsomeError

func APIKeyNotFound

func APIKeyNotFound() *AuthsomeError

func APIKeyRevoked

func APIKeyRevoked() *AuthsomeError

func AccountDisabled

func AccountDisabled() *AuthsomeError

func AccountLocked

func AccountLocked(reason string) *AuthsomeError

func AccountLockedWithTime added in v0.0.7

func AccountLockedWithTime(reason string, lockedUntil time.Time) *AuthsomeError

AccountLockedWithTime returns an account locked error with lockout duration info

func BadRequest

func BadRequest(msg string) *AuthsomeError

func CacheError

func CacheError(operation string, err error) *AuthsomeError

func ComplianceViolation

func ComplianceViolation(policy, reason string) *AuthsomeError

func ConcurrentSessionLimit

func ConcurrentSessionLimit() *AuthsomeError

func ConfigError

func ConfigError(key string, err error) *AuthsomeError

func Conflict

func Conflict(msg string) *AuthsomeError

func DataRetentionViolation

func DataRetentionViolation(reason string) *AuthsomeError

func DatabaseError

func DatabaseError(operation string, err error) *AuthsomeError

func DeviceBlocked

func DeviceBlocked() *AuthsomeError

func DeviceNotFound

func DeviceNotFound() *AuthsomeError

func DeviceNotTrusted

func DeviceNotTrusted() *AuthsomeError

func EmailAlreadyExists

func EmailAlreadyExists(email string) *AuthsomeError

func EmailNotVerified

func EmailNotVerified(email string) *AuthsomeError

func InsufficientRole

func InsufficientRole(required string) *AuthsomeError

func InternalError

func InternalError(err error) *AuthsomeError

func InternalServerError

func InternalServerError(msg string, err error) *AuthsomeError

func InternalServerErrorWithMessage

func InternalServerErrorWithMessage(msg string) *AuthsomeError

func InvalidCredentials

func InvalidCredentials() *AuthsomeError

func InvalidCredentialsWithAttempts added in v0.0.7

func InvalidCredentialsWithAttempts(attemptsRemaining int) *AuthsomeError

InvalidCredentialsWithAttempts returns invalid credentials error with remaining attempts warning

func InvalidEmail

func InvalidEmail(email string) *AuthsomeError

func InvalidFormat

func InvalidFormat(field, expectedFormat string) *AuthsomeError

func InvalidInput

func InvalidInput(field, reason string) *AuthsomeError

func InvalidOAuthState

func InvalidOAuthState() *AuthsomeError

func InvalidOTP

func InvalidOTP() *AuthsomeError

func InvalidPhone

func InvalidPhone(phone string) *AuthsomeError

func InvalidPolicy

func InvalidPolicy(reason string) *AuthsomeError

func InvalidSlug

func InvalidSlug(slug string) *AuthsomeError

func InvalidToken

func InvalidToken() *AuthsomeError

func InvalidUsername

func InvalidUsername(username string) *AuthsomeError

func InvitationAccepted

func InvitationAccepted() *AuthsomeError

func InvitationCancelled

func InvitationCancelled() *AuthsomeError

func InvitationExpired

func InvitationExpired() *AuthsomeError

func InvitationNotFound

func InvitationNotFound() *AuthsomeError

func MagicLinkExpired

func MagicLinkExpired() *AuthsomeError

func MagicLinkInvalid

func MagicLinkInvalid() *AuthsomeError

func New

func New(code, message string, httpStatus int) *AuthsomeError

New creates a new AuthsomeError with the given parameters.

func NotFound

func NotFound(msg string) *AuthsomeError

func NotImplemented

func NotImplemented(feature string) *AuthsomeError

func NotMember

func NotMember() *AuthsomeError

func NotTeamMember

func NotTeamMember() *AuthsomeError

func NotificationFailed

func NotificationFailed(err error) *AuthsomeError

func OAuthFailed

func OAuthFailed(provider, reason string) *AuthsomeError

func OAuthProviderError

func OAuthProviderError(provider string, err error) *AuthsomeError

func OIDCError

func OIDCError(reason string) *AuthsomeError

func OTPExpired

func OTPExpired() *AuthsomeError

func OrganizationExists

func OrganizationExists(identifier string) *AuthsomeError

func OrganizationLimitReached

func OrganizationLimitReached(limit int) *AuthsomeError

func OrganizationNotFound

func OrganizationNotFound() *AuthsomeError

func PasskeyNotFound

func PasskeyNotFound() *AuthsomeError

func PasskeyRegistrationFailed

func PasskeyRegistrationFailed(reason string) *AuthsomeError

func PasskeyVerificationFailed

func PasskeyVerificationFailed(reason string) *AuthsomeError

func PasswordExpired

func PasswordExpired() *AuthsomeError

func PermissionDenied

func PermissionDenied(action, resource string) *AuthsomeError

func PhoneAlreadyExists

func PhoneAlreadyExists(phone string) *AuthsomeError

func PluginDisabled

func PluginDisabled(pluginID string) *AuthsomeError

func PluginInitFailed

func PluginInitFailed(pluginID string, err error) *AuthsomeError

func PluginNotFound

func PluginNotFound(pluginID string) *AuthsomeError

func PolicyViolation

func PolicyViolation(policy, reason string) *AuthsomeError

func RateLimitExceeded

func RateLimitExceeded(retryAfter time.Duration) *AuthsomeError

func RequiredField

func RequiredField(field string) *AuthsomeError

func RoleAlreadyExists

func RoleAlreadyExists(role string) *AuthsomeError

func RoleNotFound

func RoleNotFound(role string) *AuthsomeError

func SAMLError

func SAMLError(reason string) *AuthsomeError

func SCIMInvalidFilter

func SCIMInvalidFilter(filter string) *AuthsomeError

func SCIMInvalidPath

func SCIMInvalidPath(path string) *AuthsomeError

func SCIMResourceNotFound

func SCIMResourceNotFound(resourceType string) *AuthsomeError

func SessionConflict

func SessionConflict() *AuthsomeError

func SessionExpired

func SessionExpired() *AuthsomeError

func SessionInvalid

func SessionInvalid() *AuthsomeError

func SessionNotFound

func SessionNotFound() *AuthsomeError

func SessionRevoked

func SessionRevoked() *AuthsomeError

func SlugAlreadyExists

func SlugAlreadyExists(slug string) *AuthsomeError

func StepUpRequired

func StepUpRequired() *AuthsomeError

func TeamAlreadyExists

func TeamAlreadyExists(name string) *AuthsomeError

func TeamNotFound

func TeamNotFound() *AuthsomeError

func TemplateNotFound

func TemplateNotFound(templateID string) *AuthsomeError

func TemplateRenderFailed

func TemplateRenderFailed(templateID string, err error) *AuthsomeError

func TokenExpired

func TokenExpired() *AuthsomeError

func TooManyAttempts

func TooManyAttempts(retryAfter time.Duration) *AuthsomeError

func TwoFactorRequired

func TwoFactorRequired() *AuthsomeError

func Unauthorized

func Unauthorized() *AuthsomeError

func UnauthorizedWithMessage

func UnauthorizedWithMessage(msg string) *AuthsomeError

func UserAlreadyExists

func UserAlreadyExists(identifier string) *AuthsomeError

func UserNotFound

func UserNotFound() *AuthsomeError

func UsernameAlreadyExists

func UsernameAlreadyExists(username string) *AuthsomeError

func ValidationFailed

func ValidationFailed(fields map[string]string) *AuthsomeError

func WeakPassword

func WeakPassword(reason string) *AuthsomeError

func WebhookDeliveryFailed

func WebhookDeliveryFailed(err error) *AuthsomeError

func WebhookNotFound

func WebhookNotFound() *AuthsomeError

func Wrap

func Wrap(err error, code, message string, httpStatus int) *AuthsomeError

Wrap wraps an existing error with authsome context.

func (*AuthsomeError) Error

func (e *AuthsomeError) Error() string

Error implements the error interface.

func (*AuthsomeError) Is

func (e *AuthsomeError) Is(target error) bool

Is implements errors.Is interface for AuthsomeError. Compares by error code.

func (*AuthsomeError) ToForgeError

func (e *AuthsomeError) ToForgeError() *forgeerrors.ForgeError

ToForgeError converts AuthsomeError to forge ForgeError for internal use.

func (*AuthsomeError) ToHTTPError

func (e *AuthsomeError) ToHTTPError() *forgeerrors.HTTPError

ToHTTPError converts AuthsomeError to forge HTTPError for handler responses.

func (*AuthsomeError) Unwrap

func (e *AuthsomeError) Unwrap() error

Unwrap returns the underlying error for errors.Unwrap.

func (*AuthsomeError) WithContext

func (e *AuthsomeError) WithContext(key string, value any) *AuthsomeError

WithContext adds context to the error.

func (*AuthsomeError) WithDetails

func (e *AuthsomeError) WithDetails(details any) *AuthsomeError

WithDetails adds structured details to the error.

func (*AuthsomeError) WithError

func (e *AuthsomeError) WithError(err error) *AuthsomeError

WithError wraps an underlying error.

func (*AuthsomeError) WithTraceID

func (e *AuthsomeError) WithTraceID(traceID string) *AuthsomeError

WithTraceID adds a trace ID for distributed tracing.

Jump to

Keyboard shortcuts

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