auth

package module
v0.29.0 Latest Latest
Warning

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

Go to latest
Published: Nov 28, 2025 License: GPL-3.0 Imports: 20 Imported by: 0

README

Auth Open in Gitpod

Tests Status Go Report Card PkgGoDev

Batteries-included authentication library for Go with ready-to-use UI pages, API endpoints, and middleware. You bring your own database and email service—we handle the rest.

✨ Features

  • 🔐 Two Authentication Flows

    • Passwordless - Email-based verification codes (recommended for security)
    • Username/Password - Traditional authentication with password storage
  • 🛡️ Production-Grade Security

    • Structured error handling with error codes (no internal details leaked)
    • CSRF protection via dracory/csrf integration
    • Rate limiting with per-IP/per-endpoint lockout
    • Session invalidation on password reset
    • Constant-time password comparison to prevent timing attacks
    • Secure cookie defaults (HttpOnly, SameSite, Secure on HTTPS)
    • Input validation and HTML escaping
    • Structured logging with log/slog for audit trails
  • 🎨 Complete UI Included

    • Pre-built HTML pages (login, registration, password reset)
    • Bootstrap-styled and customizable
    • Works out of the box
  • 🚀 JSON API Endpoints

    • Ready for SPAs and mobile apps
    • RESTful design
    • Comprehensive error handling
  • 🛡️ Authentication Middleware

    • WebAuthOrRedirectMiddleware - For web pages
    • ApiAuthOrErrorMiddleware - For API routes
    • WebAppendUserIdIfExistsMiddleware - Optional authentication
  • 🔧 Implementation Agnostic

    • Works with any database (SQL, NoSQL, in-memory)
    • Bring your own email service
    • Callback-based architecture for maximum flexibility
  • 🚦 Built-in Rate Limiting

    • Per-IP and per-endpoint limits on authentication endpoints
    • Sensible defaults (5 attempts per 15 minutes, 15-minute lockout)
    • Fully configurable or replaceable with a custom rate limiter
  • Production Ready

    • 90.2% test coverage
    • 34 comprehensive test files
    • Battle-tested security practices
    • Comprehensive critical review (see docs/critical_review.md)

📦 Installation

go get github.com/dracory/auth

🚀 Quick Start

Choose Your Flow
Passwordless (Recommended) Username/Password
auth, err := auth.NewPasswordlessAuth(
  auth.ConfigPasswordless{
    Endpoint: "/auth",
    UrlRedirectOnSuccess: "/dashboard",
    UseCookies: true,
    // ... implement callbacks
  },
)
auth, err := auth.NewUsernameAndPasswordAuth(
  auth.ConfigUsernameAndPassword{
    Endpoint: "/auth",
    UrlRedirectOnSuccess: "/dashboard",
    UseCookies: true,
    // ... implement callbacks
  },
)
Attach to Router
mux := http.NewServeMux()

// Attach auth routes
mux.HandleFunc("/auth/", auth.Router().ServeHTTP)

// Public route
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Welcome! <a href='" + auth.LinkLogin() + "'>Login</a>"))
})

// Protected route
mux.Handle("/dashboard", auth.WebAuthOrRedirectMiddleware(dashboardHandler))
Get Current User
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
    userID := auth.GetCurrentUserID(r)
    // Use userID to fetch user data from your database
    fmt.Fprintf(w, "Welcome, user %s!", userID)
}

📚 Complete Examples

Passwordless Flow
Step 1: Implement Required Functions
// Email sending
func emailSend(ctx context.Context, email string, subject string, body string) error {
    // Use your email service (SendGrid, AWS SES, SMTP, etc.)
    return yourEmailService.Send(email, subject, body)
}

// User lookup by email
func userFindByEmail(ctx context.Context, email string, options auth.UserAuthOptions) (userID string, err error) {
    // Query your database
    user, err := db.Query("SELECT id FROM users WHERE email = ?", email)
    if err != nil {
        return "", err
    }
    return user.ID, nil
}

// User registration (optional, if EnableRegistration is true)
func userRegister(ctx context.Context, email string, firstName string, lastName string, options auth.UserAuthOptions) error {
    // Insert into your database
    _, err := db.Exec("INSERT INTO users (email, first_name, last_name) VALUES (?, ?, ?)", 
        email, firstName, lastName)
    return err
}

// User logout
func userLogout(ctx context.Context, userID string, options auth.UserAuthOptions) error {
    // Remove token from your session/cache store
    return sessionStore.Delete("auth_token_" + userID)
}

// Token storage
func userStoreAuthToken(ctx context.Context, token string, userID string, options auth.UserAuthOptions) error {
    // Store in session/cache with expiration (e.g., 2 hours)
    return sessionStore.Set("auth_token_"+token, userID, 2*time.Hour)
}

// Token lookup
func userFindByAuthToken(ctx context.Context, token string, options auth.UserAuthOptions) (userID string, err error) {
    // Retrieve from session/cache
    userID, err = sessionStore.Get("auth_token_" + token)
    return userID, err
}

// Temporary key storage (for verification codes)
func tempKeySet(key string, value string, expiresSeconds int) error {
    // Store temporarily (e.g., in Redis, cache, or database)
    return cacheStore.Set(key, value, time.Duration(expiresSeconds)*time.Second)
}

func tempKeyGet(key string) (value string, err error) {
    // Retrieve temporary key
    return cacheStore.Get(key)
}
Step 2: Configure Authentication
authInstance, err := auth.NewPasswordlessAuth(auth.ConfigPasswordless{
    // Required
    Endpoint:                "/auth",
    UrlRedirectOnSuccess:    "/dashboard",
    UseCookies:              true, // OR UseLocalStorage: true
    FuncUserFindByAuthToken: userFindByAuthToken,
    FuncUserFindByEmail:     userFindByEmail,
    FuncUserLogout:          userLogout,
    FuncUserStoreAuthToken:  userStoreAuthToken,
    FuncEmailSend:           emailSend,
    FuncTemporaryKeyGet:     tempKeyGet,
    FuncTemporaryKeySet:     tempKeySet,
    
    // Optional
    EnableRegistration:           true,
    FuncUserRegister:             userRegister,
    FuncEmailTemplateLoginCode:   customLoginEmailTemplate,    // optional
    FuncEmailTemplateRegisterCode: customRegisterEmailTemplate, // optional
    FuncLayout:                   customPageLayout,             // optional
    DisableRateLimit:             false,                        // optional
    MaxLoginAttempts:             5,                            // optional
    LockoutDuration:              15 * time.Minute,             // optional
    FuncCheckRateLimit:           nil,                          // optional
})
Step 3: Setup Routes
mux := http.NewServeMux()

// Auth routes
mux.HandleFunc("/auth/", authInstance.Router().ServeHTTP)

// Public routes
mux.HandleFunc("/", homeHandler)

// Protected routes (web)
mux.Handle("/dashboard", authInstance.WebAuthOrRedirectMiddleware(dashboardHandler))
mux.Handle("/profile", authInstance.WebAuthOrRedirectMiddleware(profileHandler))

// Protected routes (API)
mux.Handle("/api/data", authInstance.ApiAuthOrErrorMiddleware(apiDataHandler))

// Optional auth (works for both authenticated and guest users)
mux.Handle("/products", authInstance.WebAppendUserIdIfExistsMiddleware(productsHandler))

http.ListenAndServe(":8080", mux)
Username/Password Flow
Step 1: Implement Required Functions
// User login with password verification
func userLogin(ctx context.Context, username string, password string, options auth.UserAuthOptions) (userID string, err error) {
    // Query database and verify password (use bcrypt or similar)
    user, err := db.Query("SELECT id, password_hash FROM users WHERE email = ?", username)
    if err != nil {
        return "", err
    }
    
    if !bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(password)) {
        return "", errors.New("invalid credentials")
    }
    
    return user.ID, nil
}

// User registration with password
func userRegister(ctx context.Context, username string, password string, firstName string, lastName string, options auth.UserAuthOptions) error {
    // Hash password
    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return err
    }
    
    // Insert into database
    _, err = db.Exec("INSERT INTO users (email, password_hash, first_name, last_name) VALUES (?, ?, ?, ?)",
        username, hashedPassword, firstName, lastName)
    return err
}

// User lookup by username
func userFindByUsername(ctx context.Context, username string, firstName string, lastName string, options auth.UserAuthOptions) (userID string, err error) {
    // Query database (firstName and lastName used for password reset verification)
    user, err := db.Query("SELECT id FROM users WHERE email = ? AND first_name = ? AND last_name = ?",
        username, firstName, lastName)
    if err != nil {
        return "", err
    }
    return user.ID, nil
}

// Password change
func userPasswordChange(ctx context.Context, username string, newPassword string, options auth.UserAuthOptions) error {
    // Hash new password
    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
    if err != nil {
        return err
    }
    
    // Update in database
    _, err = db.Exec("UPDATE users SET password_hash = ? WHERE email = ?", hashedPassword, username)
    return err
}

// Other functions same as passwordless (userLogout, userStoreAuthToken, etc.)
Step 2: Configure Authentication
authInstance, err := auth.NewUsernameAndPasswordAuth(auth.ConfigUsernameAndPassword{
    // Required
    Endpoint:                "/auth",
    UrlRedirectOnSuccess:    "/dashboard",
    UseCookies:              true,
    FuncUserFindByAuthToken: userFindByAuthToken,
    FuncUserFindByUsername:  userFindByUsername,
    FuncUserLogin:           userLogin,
    FuncUserLogout:          userLogout,
    FuncUserStoreAuthToken:  userStoreAuthToken,
    FuncEmailSend:           emailSend,
    FuncTemporaryKeyGet:     tempKeyGet,
    FuncTemporaryKeySet:     tempKeySet,
    
    // Optional
    EnableRegistration:               true,
    EnableVerification:               true, // Require email verification
    FuncUserRegister:                 userRegister,
    FuncUserPasswordChange:           userPasswordChange,
    FuncEmailTemplatePasswordRestore: customPasswordResetEmailTemplate, // optional
    FuncLayout:                       customPageLayout,                  // optional
    DisableRateLimit:                 false,                             // optional
    MaxLoginAttempts:                 5,                                  // optional
    LockoutDuration:                  15 * time.Minute,                   // optional
    FuncCheckRateLimit:               nil,                                // optional
})

🔌 Available Endpoints

Once configured, the following endpoints are automatically available:

API Endpoints (JSON responses)
Method Endpoint Description
POST /auth/api/login Initiate login (sends code for passwordless)
POST /auth/api/login-code-verify Verify passwordless login code
POST /auth/api/logout Logout user
POST /auth/api/register Initiate registration
POST /auth/api/register-code-verify Verify registration code
POST /auth/api/restore-password Request password reset
POST /auth/api/reset-password Complete password reset
Page Endpoints (HTML responses)
Method Endpoint Description
GET /auth/login Login page
GET /auth/login-code-verify Code verification page
GET /auth/logout Logout page
GET /auth/register Registration page
GET /auth/register-code-verify Registration verification page
GET /auth/password-restore Password restore request page
GET /auth/password-reset?t=TOKEN Password reset page

🛡️ Middleware Options

WebAuthOrRedirectMiddleware

For web pages - redirects to login if not authenticated:

mux.Handle("/dashboard", auth.WebAuthOrRedirectMiddleware(dashboardHandler))
ApiAuthOrErrorMiddleware

For API endpoints - returns JSON error if not authenticated:

mux.Handle("/api/profile", auth.ApiAuthOrErrorMiddleware(profileHandler))
WebAppendUserIdIfExistsMiddleware

Optional authentication - adds userID to context if authenticated, but doesn't redirect/error:

mux.Handle("/products", auth.WebAppendUserIdIfExistsMiddleware(productsHandler))

func productsHandler(w http.ResponseWriter, r *http.Request) {
    userID := auth.GetCurrentUserID(r)
    if userID != "" {
        // Show personalized products
    } else {
        // Show public products
    }
}

🎨 Customization

Custom Email Templates
func customLoginEmailTemplate(ctx context.Context, email string, code string, options auth.UserAuthOptions) string {
    return fmt.Sprintf(`
        <h1>Your Login Code</h1>
        <p>Hi %s,</p>
        <p>Your verification code is: <strong>%s</strong></p>
        <p>This code will expire in 1 hour.</p>
    `, email, code)
}

// Use in config
FuncEmailTemplateLoginCode: customLoginEmailTemplate,
Custom Page Layout
func customPageLayout(content string) string {
    return fmt.Sprintf(`
        <!DOCTYPE html>
        <html>
        <head>
            <title>My App - Authentication</title>
            <link rel="stylesheet" href="/css/custom.css">
        </head>
        <body>
            <div class="container">
                %s
            </div>
        </body>
        </html>
    `, content)
}

// Use in config
FuncLayout: customPageLayout,

🔐 Token Storage Options

UseCookies: true,
UseLocalStorage: false,
  • Automatically set and sent with requests
  • HttpOnly for security
  • Works with server-side rendering
LocalStorage (For SPAs)
UseCookies: false,
UseLocalStorage: true,
  • Client manages token storage
  • Must send token in Authorization header
  • Better for single-page applications

🚦 Rate Limiting

All authentication endpoints (login, registration, password restore/reset, verification) are protected by rate limiting.

Defaults (in-memory limiter):

  • 5 attempts per IP and endpoint within a 15-minute sliding window
  • Further attempts are blocked for 15 minutes (HTTP 429 with Retry-After header)

These options are shared by both ConfigPasswordless and ConfigUsernameAndPassword:

// Rate limiting options (shared by both configs)
DisableRateLimit   bool                                                                                 // Set to true to disable rate limiting (not recommended for production)
FuncCheckRateLimit func(ip string, endpoint string) (allowed bool, retryAfter time.Duration, err error) // Optional: override default rate limiter
MaxLoginAttempts   int                                                                                  // Maximum attempts before lockout (default: 5)
LockoutDuration    time.Duration                                                                        // Duration for sliding window and lockout (default: 15 minutes)

Example (username/password):

authInstance, err := auth.NewUsernameAndPasswordAuth(auth.ConfigUsernameAndPassword{
    Endpoint:         "/auth",
    UrlRedirectOnSuccess: "/dashboard",

    MaxLoginAttempts: 5,
    LockoutDuration:  15 * time.Minute,

    // Optional: use your own distributed rate limiter (e.g., Redis-based)
    // FuncCheckRateLimit: func(ip, endpoint string) (bool, time.Duration, error) {
    //     // ... implement custom logic
    // },
})

📖 UserAuthOptions

All callback functions are context-aware and receive both a ctx context.Context and a UserAuthOptions value with request metadata:

type UserAuthOptions struct {
    UserIp    string  // Client IP address
    UserAgent string  // Client user agent
}

Use this together with ctx for audit logging, security checks, or analytics:

func userLogin(ctx context.Context, username string, password string, options auth.UserAuthOptions) (userID string, err error) {
    // Log login attempt with structured logging (see Structured Logging section)
    slog.Info("login attempt",
        "ip", options.UserIp,
        "user_agent", options.UserAgent,
    )

    // Your login logic...
}

📊 Structured Logging

The library uses Go's log/slog package for structured logging in core flows.

  • Both configuration structs accept an optional logger:

    type ConfigPasswordless struct {
        // ... other fields ...
        Logger *slog.Logger // Optional: structured logger
    }
    
    type ConfigUsernameAndPassword struct {
        // ... other fields ...
        Logger *slog.Logger // Optional: structured logger
    }
    
  • If Logger is nil, the constructors fall back to slog.Default().

  • The internal Auth instance keeps this logger and uses it to log:

    • Email send failures
    • Token generation/store errors
    • Password restore failures
    • Other internal errors along with email, user_id, ip, and user_agent where available
Example: JSON structured logging
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
}))

authInstance, err := auth.NewUsernameAndPasswordAuth(auth.ConfigUsernameAndPassword{
    Endpoint:             "/auth",
    UrlRedirectOnSuccess: "/dashboard",
    UseCookies:           true,

    Logger: logger, // Pass your structured logger here

    // ... required callbacks ...
})
if err != nil {
    log.Fatal(err)
}

🔍 Helper Methods

// Get current authenticated user ID from request context
userID := auth.GetCurrentUserID(r)

// URL helpers
loginURL := auth.LinkLogin()
registerURL := auth.LinkRegister()
logoutURL := auth.LinkLogout()
passwordRestoreURL := auth.LinkPasswordRestore()
passwordResetURL := auth.LinkPasswordReset(token)

// API URL helpers
apiLoginURL := auth.LinkApiLogin()
apiRegisterURL := auth.LinkApiRegister()
apiLogoutURL := auth.LinkApiLogout()

// Enable/disable registration dynamically
auth.RegistrationEnable()
auth.RegistrationDisable()

❓ Frequently Asked Questions

Q: Can I use email instead of username?
A: Yes! The "username" parameter accepts email addresses. Most modern apps use email for authentication.

Q: Can I run multiple auth instances?
A: Yes! You can have separate instances for different user types:

// Regular users with passwordless
userAuth, _ := auth.NewPasswordlessAuth(...)
mux.HandleFunc("/auth/", userAuth.Router().ServeHTTP)

// Admins with username/password
adminAuth, _ := auth.NewUsernameAndPasswordAuth(...)
mux.HandleFunc("/admin/auth/", adminAuth.Router().ServeHTTP)

Q: How do I customize the UI?
A: Provide a custom FuncLayout function to wrap the content with your own HTML/CSS.

Q: What databases are supported?
A: Any! You implement the storage callbacks, so it works with PostgreSQL, MySQL, MongoDB, Redis, or even in-memory stores.

Q: Is this production-ready?
A: Yes! The library has:

  • 90.2% test coverage with comprehensive test suite
  • Structured error handling with error codes (no internal details leaked)
  • CSRF protection and rate limiting
  • Session invalidation on password reset
  • Secure cookie defaults and input validation
  • Structured logging for audit trails
  • See docs/critical_review.md for detailed security assessment

Q: How do I handle password reset?
A: The library includes built-in password reset flow. Users enter their email, receive a reset link, and set a new password.

Q: Can I use this with an existing user system?
A: Absolutely! Just implement the callback functions to integrate with your existing database schema.

🧪 Testing

The library includes comprehensive tests. Run them with:

go test -v ./...

For coverage:

go test -cover ./...

📝 Working Example

Check the development directory for a complete working example with:

  • Both authentication flows
  • JSON file storage (Scribble)
  • Email sending
  • All callbacks implemented

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

See LICENSE file for details.


Made with ❤️ by the Dracory team

Documentation

Index

Constants

View Source
const (
	CookieName = "authtoken"

	// PathApiLogin contains the path to api login endpoint
	PathApiLogin string = "api/login"

	// PathApiLoginCodeVerify contains the path to api login code verification endpoint
	PathApiLoginCodeVerify string = "api/login-code-verify"

	// PathApiLogout contains the path to api logout endpoint
	PathApiLogout string = "api/logout"

	// PathApiRegister contains the path to api register endpoint
	PathApiRegister string = "api/register"

	// PathApiRegisterCodeVerify contains the path to api register code verification endpoint
	PathApiRegisterCodeVerify string = "api/register-code-verify"

	// PathApiRestorePassword contains the path to api restore password endpoint
	PathApiRestorePassword string = "api/restore-password"

	// PathApiResetPassword contains the path to api reset password endpoint
	PathApiResetPassword string = "api/reset-password"

	// PathLogin contains the path to login page
	PathLogin string = "login"

	// PathLoginCodeVerify contains the path to login code verification page
	PathLoginCodeVerify string = "login-code-verify"

	// PathLogout contains the path to logout page
	PathLogout string = "logout"

	// PathRegister contains the path to logout page
	PathRegister string = "register"

	// PathRegisterCodeVerify contains the path to registration code verification page
	PathRegisterCodeVerify string = "register-code-verify"

	// PathRestore contains the path to password restore page
	PathPasswordRestore string = "password-restore"

	// PathReset contains the path to password reset page
	PathPasswordReset string = "password-reset"

	// LoginCodeLength specified the length of the login code
	LoginCodeLength int = 8

	// LoginCodeGamma specifies the characters to be used for building the login code
	LoginCodeGamma string = "BCDFGHJKLMNPQRSTVXYZ"

	DefaultVerificationCodeExpiration = 1 * time.Hour
	DefaultPasswordResetExpiration    = 1 * time.Hour
	DefaultAuthTokenExpiration        = 2 * time.Hour

	DefaultMaxLoginAttempts = 5
	DefaultLockoutDuration  = 15 * time.Minute
)
View Source
const (
	ErrCodeEmailSendFailed      = "EMAIL_SEND_FAILED"
	ErrCodeTokenStoreFailed     = "TOKEN_STORE_FAILED"
	ErrCodeValidationFailed     = "VALIDATION_FAILED"
	ErrCodeAuthenticationFailed = "AUTHENTICATION_FAILED"
	ErrCodeRegistrationFailed   = "REGISTRATION_FAILED"
	ErrCodeLogoutFailed         = "LOGOUT_FAILED"
	ErrCodeInternalError        = "INTERNAL_ERROR"
	ErrCodeCodeGenerationFailed = "CODE_GENERATION_FAILED"
	ErrCodeSerializationFailed  = "SERIALIZATION_FAILED"
	ErrCodePasswordResetFailed  = "PASSWORD_RESET_FAILED"
)

Error codes for consistent error handling

Variables

This section is empty.

Functions

func AuthCookieGet

func AuthCookieGet(r *http.Request) string

func AuthCookieRemove

func AuthCookieRemove(w http.ResponseWriter, r *http.Request)

func AuthCookieSet

func AuthCookieSet(w http.ResponseWriter, r *http.Request, token string)

func AuthTokenRetrieve

func AuthTokenRetrieve(r *http.Request, useCookies bool) string

authTokenRetrieve retrieves the auth token from the request Several attempts are made:

  1. From cookie
  2. Authorization header (aka Bearer token)
  3. Request param "api_key"
  4. Request param "token"

Types

type Auth

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

Auth defines the structure for the authentication

func NewPasswordlessAuth

func NewPasswordlessAuth(config ConfigPasswordless) (*Auth, error)

func NewUsernameAndPasswordAuth

func NewUsernameAndPasswordAuth(config ConfigUsernameAndPassword) (*Auth, error)

func (Auth) ApiAuthOrErrorMiddleware

func (a Auth) ApiAuthOrErrorMiddleware(next http.Handler) http.Handler

ApiAuthOrErrorMiddleware checks that an authentication token exists, and then finds the userID based on it. On success appends the user ID to the context. On failure it will return an unauthenticated JSON response.

func (Auth) AuthHandler

func (a Auth) AuthHandler(w http.ResponseWriter, r *http.Request)

Router routes the requests

func (Auth) GetCurrentUserID

func (a Auth) GetCurrentUserID(r *http.Request) string

func (Auth) Handler

func (a Auth) Handler() http.Handler

func (Auth) LinkApiLogin

func (a Auth) LinkApiLogin() string

func (Auth) LinkApiLoginCodeVerify

func (a Auth) LinkApiLoginCodeVerify() string

func (Auth) LinkApiLogout

func (a Auth) LinkApiLogout() string

func (Auth) LinkApiPasswordReset

func (a Auth) LinkApiPasswordReset() string

func (Auth) LinkApiPasswordRestore

func (a Auth) LinkApiPasswordRestore() string

func (Auth) LinkApiRegister

func (a Auth) LinkApiRegister() string

func (Auth) LinkApiRegisterCodeVerify

func (a Auth) LinkApiRegisterCodeVerify() string

func (Auth) LinkLogin

func (a Auth) LinkLogin() string

func (Auth) LinkLoginCodeVerify

func (a Auth) LinkLoginCodeVerify() string

func (Auth) LinkLogout

func (a Auth) LinkLogout() string

func (Auth) LinkPasswordReset

func (a Auth) LinkPasswordReset(token string) string

LinkPasswordReset - returns the password reset URL

func (Auth) LinkPasswordRestore

func (a Auth) LinkPasswordRestore() string

func (Auth) LinkRedirectOnSuccess

func (a Auth) LinkRedirectOnSuccess() string

LinkRedirectOnSuccess - returns the URL to where the user will be redirected after successful registration

func (Auth) LinkRegister

func (a Auth) LinkRegister() string

LinkRegister - returns the registration URL

func (Auth) LinkRegisterCodeVerify

func (a Auth) LinkRegisterCodeVerify() string

LinkRegisterCodeVerify - returns the registration code verification URL

func (Auth) LoginWithUsernameAndPassword

func (a Auth) LoginWithUsernameAndPassword(ctx context.Context, email string, password string, options UserAuthOptions) (response LoginUsernameAndPasswordResponse)

func (Auth) RegisterWithUsernameAndPassword

func (a Auth) RegisterWithUsernameAndPassword(ctx context.Context, email string, password string, firstName string, lastName string, options UserAuthOptions) (response RegisterUsernameAndPasswordResponse)

func (*Auth) RegistrationDisable

func (a *Auth) RegistrationDisable()

RegistrationDisable - disables registration

func (*Auth) RegistrationEnable

func (a *Auth) RegistrationEnable()

RegistrationEnable - enables registration

func (Auth) Router

func (a Auth) Router() *http.ServeMux

func (Auth) WebAppendUserIdIfExistsMiddleware

func (a Auth) WebAppendUserIdIfExistsMiddleware(next http.Handler) http.Handler

WebAppendUserIdIfExistsMiddleware appends the user ID to the context if an authentication token exists in the requests. This middleware does not have a side effect like for instance redirecting to the login endpoint. This is why it is important to be added to places which can be used by both guests and users (i.e. website pages), where authenticated users may have some extra privileges

If you need to redirect the user if authentication token not found, or the user does not exist, take a look at the WebAuthOrRedirectMiddleware middleware, which does exactly that

func (Auth) WebAuthOrRedirectMiddleware

func (a Auth) WebAuthOrRedirectMiddleware(next http.Handler) http.Handler

WebAuthOrRedirectMiddleware checks that an authentication token exists, and then finds the userID based on it. On success appends the user ID to the context. On failure it will redirect the user to the login endpoint to reauthenticate.

If you need to only find if the authentication token is successful without redirection please use the WebAppendUserIdIfExistsMiddleware which does exactly that without side effects

type AuthError added in v0.29.0

type AuthError struct {
	Code        string
	Message     string // User-facing message
	InternalErr error  // For logging only, never exposed to users
}

AuthError represents a structured authentication error with a code, user-facing message, and internal error details for logging.

func NewAuthenticationError added in v0.29.0

func NewAuthenticationError(err error) AuthError

NewAuthenticationError creates an AuthError for authentication failures.

func NewCodeGenerationError added in v0.29.0

func NewCodeGenerationError(err error) AuthError

NewCodeGenerationError creates an AuthError for code generation failures.

func NewEmailSendError added in v0.29.0

func NewEmailSendError(err error) AuthError

NewEmailSendError creates an AuthError for email send failures.

func NewInternalError added in v0.29.0

func NewInternalError(err error) AuthError

NewInternalError creates an AuthError for generic internal errors.

func NewLogoutError added in v0.29.0

func NewLogoutError(err error) AuthError

NewLogoutError creates an AuthError for logout failures.

func NewPasswordResetError added in v0.29.0

func NewPasswordResetError(err error) AuthError

NewPasswordResetError creates an AuthError for password reset failures.

func NewRegistrationError added in v0.29.0

func NewRegistrationError(err error) AuthError

NewRegistrationError creates an AuthError for registration failures.

func NewSerializationError added in v0.29.0

func NewSerializationError(err error) AuthError

NewSerializationError creates an AuthError for data serialization failures.

func NewTokenStoreError added in v0.29.0

func NewTokenStoreError(err error) AuthError

NewTokenStoreError creates an AuthError for token store failures.

func (AuthError) Error added in v0.29.0

func (e AuthError) Error() string

Error implements the error interface, returning the user-facing message.

type AuthenticatedUserID

type AuthenticatedUserID struct{}

type ConfigPasswordless

type ConfigPasswordless struct {

	// ===== START: shared by all implementations
	EnableRegistration      bool
	Endpoint                string
	FuncLayout              func(content string) string
	FuncTemporaryKeyGet     func(key string) (value string, err error)
	FuncTemporaryKeySet     func(key string, value string, expiresSeconds int) (err error)
	FuncUserFindByAuthToken func(ctx context.Context, sessionID string, options UserAuthOptions) (userID string, err error)
	FuncUserLogout          func(ctx context.Context, userID string, options UserAuthOptions) (err error)
	FuncUserStoreAuthToken  func(ctx context.Context, sessionID string, userID string, options UserAuthOptions) error
	UrlRedirectOnSuccess    string
	UseCookies              bool
	UseLocalStorage         bool
	CookieConfig            *CookieConfig
	// Rate limiting options
	DisableRateLimit   bool                                                                                 // Set to true to disable rate limiting (not recommended for production)
	FuncCheckRateLimit func(ip string, endpoint string) (allowed bool, retryAfter time.Duration, err error) // Optional: override default rate limiter
	MaxLoginAttempts   int                                                                                  // Maximum attempts before lockout (default: 5)
	LockoutDuration    time.Duration                                                                        // Duration to lock after max attempts (default: 15 minutes)
	// CSRF Protection
	EnableCSRFProtection bool
	CSRFSecret           string
	Logger               *slog.Logger

	// ===== START: passwordless options
	FuncUserFindByEmail           func(ctx context.Context, email string, options UserAuthOptions) (userID string, err error)
	FuncEmailTemplateLoginCode    func(ctx context.Context, email string, logingLink string, options UserAuthOptions) string   // optional
	FuncEmailTemplateRegisterCode func(ctx context.Context, email string, registerLink string, options UserAuthOptions) string // optional
	FuncEmailSend                 func(ctx context.Context, email string, emailSubject string, emailBody string) (err error)
	FuncUserRegister              func(ctx context.Context, email string, firstName string, lastName string, options UserAuthOptions) (err error)
}

type ConfigUsernameAndPassword

type ConfigUsernameAndPassword struct {
	// ===== START: shared by all implementations
	EnableRegistration      bool
	Endpoint                string
	FuncLayout              func(content string) string
	FuncTemporaryKeyGet     func(key string) (value string, err error)
	FuncTemporaryKeySet     func(key string, value string, expiresSeconds int) (err error)
	FuncUserStoreAuthToken  func(ctx context.Context, sessionID string, userID string, options UserAuthOptions) error
	FuncUserFindByAuthToken func(ctx context.Context, sessionID string, options UserAuthOptions) (userID string, err error)
	UrlRedirectOnSuccess    string
	UseCookies              bool
	UseLocalStorage         bool
	CookieConfig            *CookieConfig
	// Rate limiting options
	DisableRateLimit   bool                                                                                 // Set to true to disable rate limiting (not recommended for production)
	FuncCheckRateLimit func(ip string, endpoint string) (allowed bool, retryAfter time.Duration, err error) // Optional: override default rate limiter
	MaxLoginAttempts   int                                                                                  // Maximum attempts before lockout (default: 5)
	LockoutDuration    time.Duration                                                                        // Duration to lock after max attempts (default: 15 minutes)
	// CSRF Protection
	EnableCSRFProtection bool
	CSRFSecret           string
	Logger               *slog.Logger

	// ===== START: username(email) and password options
	EnableVerification               bool
	FuncEmailTemplatePasswordRestore func(ctx context.Context, userID string, passwordRestoreLink string, options UserAuthOptions) string // optional
	FuncEmailTemplateRegisterCode    func(ctx context.Context, userID string, passwordRestoreLink string, options UserAuthOptions) string // optional
	FuncEmailSend                    func(ctx context.Context, userID string, emailSubject string, emailBody string) (err error)
	FuncUserFindByUsername           func(ctx context.Context, username string, firstName string, lastName string, options UserAuthOptions) (userID string, err error)
	FuncUserLogin                    func(ctx context.Context, username string, password string, options UserAuthOptions) (userID string, err error)
	FuncUserLogout                   func(ctx context.Context, userID string, options UserAuthOptions) (err error)
	FuncUserPasswordChange           func(ctx context.Context, username string, newPassword string, options UserAuthOptions) (err error)
	FuncUserRegister                 func(ctx context.Context, username string, password string, first_name string, last_name string, options UserAuthOptions) (err error)
	PasswordStrength                 *authtypes.PasswordStrengthConfig
	LabelUsername                    string
}

Config defines the available configuration options for authentication

type CookieConfig added in v0.29.0

type CookieConfig struct {
	HttpOnly bool
	Secure   bool
	SameSite http.SameSite
	MaxAge   int
	Domain   string
	Path     string
}

type LoginUsernameAndPasswordResponse

type LoginUsernameAndPasswordResponse struct {
	ErrorMessage   string
	SuccessMessage string
	Token          string
}

type RegisterUsernameAndPasswordResponse

type RegisterUsernameAndPasswordResponse struct {
	ErrorMessage   string
	SuccessMessage string
	Token          string
}

type UserAuthOptions

type UserAuthOptions struct {
	UserIp    string
	UserAgent string
}

Directories

Path Synopsis
scribble
Package scribble is a tiny JSON database
Package scribble is a tiny JSON database

Jump to

Keyboard shortcuts

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