Files
golib/hwsauth/authenticator.go
Haelnorr 1b25e2f0a5 Refactor database interface to use *sql.DB directly
Simplified the database layer by removing custom interface wrappers
and using standard library *sql.DB and *sql.Tx types directly.

Changes:
- Removed DBConnection and DBTransaction interfaces from database.go
- Removed NewDBConnection() wrapper function
- Updated TokenGenerator to use *sql.DB instead of DBConnection
- Updated all validation and revocation methods to accept *sql.Tx
- Updated TableManager to work with *sql.DB directly
- Updated all tests to use db.Begin() instead of custom wrappers
- Fixed GeneratorConfig.DB field (was DBConn)
- Updated documentation in doc.go with correct API usage

Benefits:
- Simpler API with fewer abstractions
- Works directly with database/sql standard library
- Compatible with GORM (via gormDB.DB()) and Bun (share same *sql.DB)
- Easier to understand and maintain
- No unnecessary wrapper layers

Breaking changes:
- GeneratorConfig.DBConn renamed to GeneratorConfig.DB
- Removed NewDBConnection() function - pass *sql.DB directly
- ValidateAccess/ValidateRefresh now accept *sql.Tx instead of DBTransaction
- Token.Revoke/CheckNotRevoked now accept *sql.Tx instead of DBTransaction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 17:39:30 +11:00

118 lines
3.1 KiB
Go

package hwsauth
import (
"database/sql"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/jwt"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)
type Authenticator[T Model] struct {
tokenGenerator *jwt.TokenGenerator
load LoadFunc[T]
conn DBConnection
ignoredPaths []string
logger *zerolog.Logger
server *hws.Server
errorPage hws.ErrorPageFunc
SSL bool // Use SSL for JWT tokens. Default true
LandingPage string // Path of the desired landing page for logged in users
}
// NewAuthenticator creates and returns a new Authenticator using the provided configuration.
// If cfg is nil or any required fields are not set, default values will be used or an error returned.
// Required fields: SecretKey (no default)
// If SSL is true, TrustedHost is also required.
func NewAuthenticator[T Model](
cfg *Config,
load LoadFunc[T],
server *hws.Server,
conn DBConnection,
logger *zerolog.Logger,
errorPage hws.ErrorPageFunc,
) (*Authenticator[T], error) {
if load == nil {
return nil, errors.New("No function to load model supplied")
}
if server == nil {
return nil, errors.New("No hws.Server provided")
}
if conn == nil {
return nil, errors.New("No database connection supplied")
}
if logger == nil {
return nil, errors.New("No logger provided")
}
if errorPage == nil {
return nil, errors.New("No ErrorPage provided")
}
// Validate config
if cfg == nil {
return nil, errors.New("Config is required")
}
if cfg.SecretKey == "" {
return nil, errors.New("SecretKey is required")
}
if cfg.SSL && cfg.TrustedHost == "" {
return nil, errors.New("TrustedHost is required when SSL is enabled")
}
if cfg.AccessTokenExpiry == 0 {
cfg.AccessTokenExpiry = 5
}
if cfg.RefreshTokenExpiry == 0 {
cfg.RefreshTokenExpiry = 1440
}
if cfg.TokenFreshTime == 0 {
cfg.TokenFreshTime = 5
}
if cfg.LandingPage == "" {
cfg.LandingPage = "/profile"
}
// Cast DBConnection to *sql.DB
// DBConnection is satisfied by *sql.DB, so this cast should be safe for standard usage
sqlDB, ok := conn.(*sql.DB)
if !ok {
return nil, errors.New("DBConnection must be *sql.DB for JWT token generation")
}
// Configure JWT table
tableConfig := jwt.DefaultTableConfig()
if cfg.JWTTableName != "" {
tableConfig.TableName = cfg.JWTTableName
}
// Create token generator
tokenGen, err := jwt.CreateGenerator(jwt.GeneratorConfig{
AccessExpireAfter: cfg.AccessTokenExpiry,
RefreshExpireAfter: cfg.RefreshTokenExpiry,
FreshExpireAfter: cfg.TokenFreshTime,
TrustedHost: cfg.TrustedHost,
SecretKey: cfg.SecretKey,
DBConn: sqlDB,
DBType: jwt.DatabaseType{
Type: cfg.DatabaseType,
Version: cfg.DatabaseVersion,
},
TableConfig: tableConfig,
})
if err != nil {
return nil, errors.Wrap(err, "jwt.CreateGenerator")
}
auth := Authenticator[T]{
tokenGenerator: tokenGen,
load: load,
server: server,
conn: conn,
logger: logger,
errorPage: errorPage,
SSL: cfg.SSL,
LandingPage: cfg.LandingPage,
}
return &auth, nil
}