Skip to main content

Overview

The basicauth middleware provides HTTP Basic Authentication, a simple authentication scheme built into the HTTP protocol. It prompts users for a username and password, which are sent with each request. Use it when you need:
  • Simple password protection for admin areas
  • Quick authentication for internal tools
  • Development/staging environment protection

Installation

import "github.com/go-mizu/mizu/middlewares/basicauth"

Quick Start

app := mizu.New()

// Define credentials
credentials := map[string]string{
    "admin": "secret",
    "user":  "password",
}

// Protect all routes
app.Use(basicauth.New(credentials))

// Or protect specific routes
app.Get("/admin", adminHandler, basicauth.New(credentials))

Configuration

Options

OptionTypeDefaultDescription
Realmstring"Restricted"Authentication realm shown in browser prompt
ValidatorValidatorFunc-Custom function to validate credentials
ErrorHandlerfunc(*mizu.Ctx) error-Custom handler for auth failures

ValidatorFunc

type ValidatorFunc func(username, password string) bool

Examples

Static Credentials

credentials := basicauth.Accounts{
    "admin": "secret123",
    "api":   "token456",
}

app.Use(basicauth.New(credentials))

Custom Realm

app.Use(basicauth.WithRealm("Admin Area", map[string]string{
    "admin": "secret",
}))

Custom Validator

Validate against a database or external service:
app.Use(basicauth.WithValidator(func(user, pass string) bool {
    // Query database
    dbUser, err := db.GetUser(user)
    if err != nil {
        return false
    }

    // Verify password (use proper hashing!)
    return bcrypt.CompareHashAndPassword(
        []byte(dbUser.PasswordHash),
        []byte(pass),
    ) == nil
}))

Custom Error Handler

app.Use(basicauth.WithOptions(basicauth.Options{
    Validator: func(user, pass string) bool {
        return user == "admin" && pass == "secret"
    },
    ErrorHandler: func(c *mizu.Ctx) error {
        return c.JSON(401, map[string]string{
            "error": "Invalid credentials",
        })
    },
}))

Route-Specific Protection

// Public routes
app.Get("/", publicHandler)
app.Get("/about", aboutHandler)

// Protected admin routes
adminAuth := basicauth.New(map[string]string{"admin": "secret"})
app.Get("/admin", adminDashboard, adminAuth)
app.Get("/admin/users", adminUsers, adminAuth)

Group Protection

admin := app.Group("/admin")
admin.Use(basicauth.New(map[string]string{"admin": "secret"}))

admin.Get("/", adminDashboard)
admin.Get("/users", adminUsers)
admin.Post("/users", createUser)

API Reference

Functions

// New creates middleware with static credentials
func New(credentials map[string]string) mizu.Middleware

// WithValidator creates middleware with custom validator
func WithValidator(fn ValidatorFunc) mizu.Middleware

// WithRealm creates middleware with custom realm
func WithRealm(realm string, credentials map[string]string) mizu.Middleware

// WithOptions creates middleware with full configuration
func WithOptions(opts Options) mizu.Middleware

Types

// Accounts is a convenience type for credentials
type Accounts map[string]string

Technical Details

The basicauth middleware implements HTTP Basic Authentication according to RFC 7617. Here are the key implementation details:

Authentication Flow

  1. Header Extraction: Extracts the Authorization header from the incoming request
  2. Scheme Validation: Verifies the header starts with β€œBasic ” prefix
  3. Base64 Decoding: Decodes the base64-encoded credentials using base64.StdEncoding.DecodeString()
  4. Credential Parsing: Splits the decoded string on the first colon (:) to separate username and password
  5. Validation: Calls the configured validator function to verify credentials
  6. Response: Either proceeds to the next handler or returns 401 Unauthorized with WWW-Authenticate header

Security Features

Constant-Time Comparison: The built-in validator uses secureCompare() function to prevent timing attacks:
func secureCompare(a, b string) bool {
    // Hash both strings to ensure constant time comparison
    // even for strings of different lengths
    aHash := sha256.Sum256([]byte(a))
    bHash := sha256.Sum256([]byte(b))
    return subtle.ConstantTimeCompare(aHash[:], bHash[:]) == 1
}
This approach:
  • Hashes both strings using SHA-256 to normalize lengths
  • Uses crypto/subtle.ConstantTimeCompare() to prevent timing side-channels
  • Protects against timing attacks that could leak password information
WWW-Authenticate Header: On authentication failure, the middleware sets the WWW-Authenticate header with the configured realm, prompting the browser to display a login dialog.

Error Handling

The middleware returns 401 Unauthorized in these cases:
  • Missing Authorization header
  • Invalid authorization scheme (not β€œBasic”)
  • Invalid base64 encoding
  • Malformed credentials (no colon separator)
  • Validator function returns false
Custom error handlers can be provided via Options.ErrorHandler to customize the response format (e.g., JSON instead of plain text).

Security Considerations

  1. Always use HTTPS - Basic auth sends credentials base64-encoded (not encrypted)
  2. Use strong passwords - Avoid dictionary words and short passwords
  3. Hash stored passwords - Never store plain-text passwords in your validator
  4. Consider rate limiting - Combine with ratelimit to prevent brute force attacks
  5. Timing attacks - The built-in validator uses constant-time comparison

Best Practices

  • Use Basic Auth for simple internal tools, not production user-facing auth
  • Combine with HTTPS redirect middleware
  • Add rate limiting to prevent brute force attacks
  • Use Bearer auth or session-based auth for APIs

Testing

The basicauth middleware includes comprehensive test coverage. Below are all test cases:
Test CaseDescriptionExpected Behavior
TestNew/allows valid credentialsValid username and password providedReturns 200 OK and allows request through
TestNew/rejects invalid passwordValid username with incorrect passwordReturns 401 Unauthorized
TestNew/rejects unknown userNon-existent username providedReturns 401 Unauthorized
TestNew/rejects missing authNo Authorization header presentReturns 401 Unauthorized with WWW-Authenticate header
TestWithValidatorCustom validator function with valid credentialsReturns 200 OK when validator returns true
TestWithRealmCustom realm configurationReturns 401 with WWW-Authenticate header containing custom realm
TestWithOptions_ErrorHandlerCustom error handler on auth failureCalls custom error handler returning JSON response
TestWithOptions_InvalidAuth/not basicAuthorization header with Bearer schemeReturns 401 Unauthorized
TestWithOptions_InvalidAuth/invalid base64Malformed base64 in Authorization headerReturns 401 Unauthorized
TestWithOptions_InvalidAuth/no colonBase64 credentials without colon separatorReturns 401 Unauthorized
TestWithOptions_PanicsCreating middleware without validatorPanics with error message
TestSecureCompare/password_passwordComparing identical stringsReturns true
TestSecureCompare/password_differentComparing different stringsReturns false
TestSecureCompare/short_longpasswordComparing strings of different lengthsReturns false
TestSecureCompare/empty_emptyComparing empty stringsReturns true