Documentation
¶
Index ¶
- Constants
- Variables
- type Config
- type CustomValidatorFunc
- type IsUsernameAvailableParams
- type IsUsernameAvailableResult
- type NormalizationFunc
- type Option
- func WithCustomValidator(fn CustomValidatorFunc) Option
- func WithMaxLength(maxLen int) Option
- func WithMinLength(minLen int) Option
- func WithNormalization(enable bool) Option
- func WithNormalizationFunc(fn NormalizationFunc) Option
- func WithRequireEmailVerification(require bool) Option
- func WithUsernameValidator(pattern string) Option
- type Plugin
- func (p *Plugin) Config() Config
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) IsAvailable(ctx context.Context, username string) (*IsUsernameAvailableResult, error)
- func (p *Plugin) Normalize(username string) string
- func (p *Plugin) ProcessSignUpUsername(ctx context.Context, rawUsername, rawDisplayUsername string) (normalizedUsername, finalDisplayUsername string, err error)
- func (p *Plugin) SignIn(ctx context.Context, params SignInUsernameParams) (*SignInUsernameResult, error)
- func (p *Plugin) UpdateUsername(ctx context.Context, params UpdateUsernameParams) (*UpdateUsernameResult, error)
- func (p *Plugin) ValidateUsername(ctx context.Context, username string) error
- type Repository
- type SignInUsernameParams
- type SignInUsernameResult
- type UpdateUsernameParams
- type UpdateUsernameResult
Constants ¶
const ( // EventSignInBefore is published before authenticating with username credentials. EventSignInBefore = "username:signin:before" // EventSignInAfter is published after successful authentication with username credentials. EventSignInAfter = "username:signin:after" // EventUpdateBefore is published before updating a user's username. EventUpdateBefore = "username:update:before" // EventUpdateAfter is published after updating a user's username. EventUpdateAfter = "username:update:after" )
Standard Event names for the Username plugin.
const ( FieldUsername = "username" FieldDisplayUsername = "display_username" ExtraKeyUsername = "username" ExtraKeyDisplayUsername = "display_username" )
Standard Extra metadata keys and field names for the Username plugin.
const CredentialProvider = "credential"
CredentialProvider is the default account provider ID for password authentication ("credential").
const PluginID = "username"
PluginID is the unique string identifier for the Username plugin ("username").
Variables ¶
var ( // ErrInvalidUsernameOrPassword is returned when login credentials (username + password) do not match. ErrInvalidUsernameOrPassword = errors.New("username: invalid username or password") // ErrEmailNotVerified is returned when password sign-in is attempted with an unverified email address. ErrEmailNotVerified = errors.New("username: email not verified") // ErrUsernameAlreadyTaken is returned when attempting to claim a username that is already in use. ErrUsernameAlreadyTaken = errors.New("username: username is already taken") // ErrUsernameTooShort is returned when a username does not satisfy the minimum length requirement. ErrUsernameTooShort = errors.New("username: username is too short") // ErrUsernameTooLong is returned when a username exceeds the maximum allowed length. ErrUsernameTooLong = errors.New("username: username is too long") // ErrInvalidUsername is returned when a username fails character set regex validation. ErrInvalidUsername = errors.New("username: invalid username format") // ErrInvalidDisplayUsername is returned when a display username fails format requirements. ErrInvalidDisplayUsername = errors.New("username: invalid display username format") // ErrUserNotFound is returned when no user matches the queried username or ID. ErrUserNotFound = errors.New("username: user not found") // ErrCredentialAccountNotFound is returned when credential provider credentials are missing for a user. ErrCredentialAccountNotFound = errors.New("username: credential account not found") // ErrInvalidParameter is returned when a required parameter is missing or invalid. ErrInvalidParameter = errors.New("username: required parameter is missing or invalid") )
Sentinel errors for the Username plugin.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// MinLength specifies the minimum allowed username length (default: 3).
MinLength int
// MaxLength specifies the maximum allowed username length (default: 30).
MaxLength int
// RegexValidator is the compiled regular expression used to validate format (default: ^[a-zA-Z0-9_.]+$).
RegexValidator *regexp.Regexp
// CustomValidator is an optional user-defined function for advanced username validation (e.g. reserved word check).
CustomValidator CustomValidatorFunc
// EnableNormalization determines whether username strings are automatically normalized (default: true).
EnableNormalization bool
// NormalizeFunc defines the normalization routine applied to usernames (default: strings.ToLower).
NormalizeFunc NormalizationFunc
// RequireEmailVerification enforces that user emails must be verified before username sign-in (default: false).
RequireEmailVerification bool
}
Config holds all configuration parameters for the Username plugin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default configuration settings for the Username plugin.
type CustomValidatorFunc ¶
CustomValidatorFunc defines a custom validation function signature for username validation.
type IsUsernameAvailableParams ¶
type IsUsernameAvailableParams struct {
// Username is the username candidate to check.
Username string `json:"username"`
plugin.ExtraContainer
}
IsUsernameAvailableParams defines parameters to check if a username is free for registration.
type IsUsernameAvailableResult ¶
type IsUsernameAvailableResult struct {
// Available indicates whether the queried username is free.
Available bool `json:"available"`
// Username is the processed username being queried.
Username string `json:"username"`
}
IsUsernameAvailableResult reports username availability.
type NormalizationFunc ¶
NormalizationFunc defines a function signature for normalizing username input.
type Option ¶
type Option func(*Config)
Option defines a functional option signature for configuring the Username plugin.
func WithCustomValidator ¶
func WithCustomValidator(fn CustomValidatorFunc) Option
WithCustomValidator attaches an asynchronous custom validator callback.
func WithMaxLength ¶
WithMaxLength sets the maximum allowed username length.
func WithMinLength ¶
WithMinLength sets the minimum allowed username length.
func WithNormalization ¶
WithNormalization enables or disables automatic username normalization.
func WithNormalizationFunc ¶
func WithNormalizationFunc(fn NormalizationFunc) Option
WithNormalizationFunc sets a custom normalization routine (e.g. lowercasing / trimming).
func WithRequireEmailVerification ¶
WithRequireEmailVerification configures whether email verification is required prior to sign-in.
func WithUsernameValidator ¶
WithUsernameValidator sets a custom regex pattern string for format validation.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements the username authentication plugin for go-modular-auth.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New instantiates a new Username plugin configured with the given repository and options.
func (*Plugin) IsAvailable ¶
func (p *Plugin) IsAvailable(ctx context.Context, username string) (*IsUsernameAvailableResult, error)
IsAvailable checks whether the specified username is free for registration.
func (*Plugin) Normalize ¶
Normalize applies the configured normalization routine to a username string (e.g. lowercasing).
func (*Plugin) ProcessSignUpUsername ¶
func (p *Plugin) ProcessSignUpUsername(ctx context.Context, rawUsername, rawDisplayUsername string) (normalizedUsername, finalDisplayUsername string, err error)
ProcessSignUpUsername validates, normalizes, and prepares username & displayUsername for user registration. If displayUsername is empty, it defaults to the unnormalized or normalized username.
func (*Plugin) SignIn ¶
func (p *Plugin) SignIn(ctx context.Context, params SignInUsernameParams) (*SignInUsernameResult, error)
SignIn authenticates a user by username and password. Employs a dummy bcrypt check on nonexistent users to prevent timing attacks.
func (*Plugin) UpdateUsername ¶
func (p *Plugin) UpdateUsername(ctx context.Context, params UpdateUsernameParams) (*UpdateUsernameResult, error)
UpdateUsername validates and modifies the username and displayUsername for a user entity.
type Repository ¶
type Repository interface {
// GetUserByUsername retrieves a user entity matching the provided username.
//
// Function:
// Used during username + password sign-in to locate the target user.
//
// Storage:
// Database (GORM / SQL) - Query user by case-insensitive username index.
//
// Arguments:
// - ctx: Request cancellation context.
// - username: Username string.
//
// Returns:
// - *entity.User: Matching user entity if found.
// - error: ErrUserNotFound if missing, or database error.
//
// Example SQL:
// SELECT id, username, display_username, email, name, email_verified, created_at, updated_at FROM users WHERE LOWER(username) = LOWER($1) LIMIT 1;
GetUserByUsername(ctx context.Context, username string) (*entity.User, error)
// GetUserByID retrieves a user entity matching the provided unique identifier.
//
// Function:
// Used when retrieving user details during username updates or profile management.
//
// Storage:
// Database (GORM / SQL) - User primary key lookup.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: Target user primary key ID.
//
// Returns:
// - *entity.User: Matching user entity if found.
// - error: ErrUserNotFound if missing.
//
// Example SQL:
// SELECT id, username, display_username, email, name, email_verified, created_at, updated_at FROM users WHERE id = $1 LIMIT 1;
GetUserByID(ctx context.Context, userID string) (*entity.User, error)
// IsUsernameAvailable checks if a given username is unregistered and available for use.
//
// Function:
// Called prior to assigning or changing a username to prevent duplicate username claims.
//
// Storage:
// Database (GORM / SQL) - Unique username count check.
//
// Arguments:
// - ctx: Request cancellation context.
// - username: Proposed username string.
//
// Returns:
// - bool: True if available (unclaimed), false if already taken.
// - error: Nil on success, or database error.
//
// Example SQL:
// SELECT COUNT(*) FROM users WHERE LOWER(username) = LOWER($1);
IsUsernameAvailable(ctx context.Context, username string) (bool, error)
// UpdateUsername updates the username and display_username fields for a user.
//
// Function:
// Called when a user modifies their handle or display username.
//
// Storage:
// Database (GORM / SQL) - User handle update.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: Target user ID.
// - username: Normalized lowercase username.
// - displayUsername: Original casing display username.
//
// Returns:
// - error: ErrUsernameAlreadyTaken on constraint conflict.
//
// Example SQL:
// UPDATE users SET username = $1, display_username = $2, updated_at = $3 WHERE id = $4;
UpdateUsername(ctx context.Context, userID, username, displayUsername string) error
// GetAccountByUserIDAndProvider retrieves provider credentials matching a user ID and provider ("credential").
//
// Function:
// Used during username sign-in to fetch stored password hash for verification.
//
// Storage:
// Database (GORM / SQL) - Credentials record lookup.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: User ID.
// - providerID: Provider string ("credential").
//
// Returns:
// - *entity.Account: Account entity containing PasswordHash.
// - error: ErrCredentialAccountNotFound if missing.
//
// Example SQL:
// SELECT id, user_id, provider, password_hash FROM accounts WHERE user_id = $1 AND provider = $2 LIMIT 1;
GetAccountByUserIDAndProvider(ctx context.Context, userID, providerID string) (*entity.Account, error)
// CreateSession persists a new active user session in storage.
//
// Function:
// Called after successful username + password verification to issue a session.
//
// Storage:
// Database (GORM / SQL) - Active session creation.
//
// Arguments:
// - ctx: Request cancellation context.
// - params: Session creation parameters.
//
// Returns:
// - *entity.Session: Active session entity.
// - error: Nil on success.
//
// Example SQL:
// INSERT INTO sessions (id, user_id, token, expires_at, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6);
CreateSession(ctx context.Context, params *dto.CreateSessionParams) (*entity.Session, error)
}
Repository defines the persistent storage contract required by the Username plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, MongoDB, GORM).
Implementation Example (GORM / database/sql): ¶
type GormUsernameRepository struct {
db *gorm.DB
}
func (r *GormUsernameRepository) GetUserByUsername(ctx context.Context, username string) (*entity.User, error) {
var u entity.User
if err := r.db.WithContext(ctx).Where("LOWER(username) = LOWER(?)", username).First(&u).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, username.ErrUserNotFound
}
return nil, err
}
return &u, nil
}
type SignInUsernameParams ¶
type SignInUsernameParams struct {
// Username is the target account username (required).
Username string `json:"username"`
// Password is the plain text user password (required).
Password string `json:"password"`
// RememberMe extends session lifespan if true.
RememberMe *bool `json:"remember_me,omitempty"`
plugin.ExtraContainer
}
SignInUsernameParams defines input parameters to authenticate a user using username and password.
type SignInUsernameResult ¶
type SignInUsernameResult struct {
// User is the authenticated user entity.
User *entity.User `json:"user"`
// SessionToken is the raw unique session token string.
SessionToken string `json:"session_token"`
// Session is the persisted active session entity.
Session *entity.Session `json:"session"`
}
SignInUsernameResult contains the authenticated user entity and session details.
type UpdateUsernameParams ¶
type UpdateUsernameParams struct {
// UserID is the unique identifier of the user (required).
UserID string `json:"user_id"`
// Username is the new username string (required).
Username string `json:"username"`
// DisplayUsername is the optional display username (defaults to Username if empty).
DisplayUsername string `json:"display_username,omitempty"`
plugin.ExtraContainer
}
UpdateUsernameParams defines parameters to update a user's username and display_username.
type UpdateUsernameResult ¶
type UpdateUsernameResult struct {
// Success indicates if the username update completed successfully.
Success bool `json:"success"`
// User is the updated user entity.
User *entity.User `json:"user"`
}
UpdateUsernameResult reports the result of updating a username.