Documentation
¶
Overview ¶
Package emailpassword defines event constants and typed event payloads published by the EmailPassword plugin.
Package emailpassword provides functional options and configuration settings for the EmailPassword plugin.
Index ¶
- Constants
- Variables
- type Config
- type Option
- type PasswordChangeEventPayload
- type PasswordResetCompletedEventPayload
- type PasswordResetRequestedEventPayload
- type Plugin
- func (p *Plugin) ChangePassword(ctx context.Context, input dto.ChangePasswordParams) error
- func (p *Plugin) ForgotPassword(ctx context.Context, input dto.ForgotPasswordParams) (*entity.VerificationToken, error)
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) ResetPassword(ctx context.Context, input dto.ResetPasswordParams) error
- func (p *Plugin) SignIn(ctx context.Context, input dto.SignInParams) (*entity.User, error)
- func (p *Plugin) SignUp(ctx context.Context, input dto.SignUpParams) (*entity.User, error)
- type Repository
- type SignInEventPayload
- type SignUpEventPayload
Constants ¶
const ( // PluginID is the unique string identifier for the EmailPassword plugin ("email-password"). PluginID = "email-password" // CredentialProvider is the default provider key used for password-based accounts ("credential"). CredentialProvider = "credential" )
const ( // EventSignUpBefore is emitted right before persisting a new user record. // Event listeners can inspect and mutate parameters (e.g. payload.Params.Set("role", "admin")). // Payload: *SignUpEventPayload EventSignUpBefore = "emailpassword:signup:before" // EventSignUpAfter is emitted immediately after successfully registering a user and creating their credential account. // Useful for triggering asynchronous welcome emails or provisioning external services. // Payload: *SignUpEventPayload EventSignUpAfter = "emailpassword:signup:after" // EventSignInBefore is emitted before validating credentials during sign-in. // Payload: *SignInEventPayload EventSignInBefore = "emailpassword:signin:before" // EventSignInAfter is emitted after successfully verifying user credentials and establishing a session. // Useful for security audit logs, geo-IP notifications, or analytics tracking. // Payload: *SignInEventPayload EventSignInAfter = "emailpassword:signin:after" // EventPasswordChangeBefore is emitted before updating a user's password. // Payload: *PasswordChangeEventPayload EventPasswordChangeBefore = "emailpassword:password_change:before" // EventPasswordChangeAfter is emitted after successfully updating a user's password in storage. // Payload: *PasswordChangeEventPayload EventPasswordChangeAfter = "emailpassword:password_change:after" // EventPasswordResetRequested is emitted when a secure password reset token is generated. // Essential for dispatching password reset emails containing the verification token link. // Payload: *PasswordResetRequestedEventPayload EventPasswordResetRequested = "emailpassword:password_reset:requested" // EventPasswordResetCompleted is emitted after a password has been successfully reset using a valid token. // Useful for sending security confirmation notifications. // Payload: *PasswordResetCompletedEventPayload EventPasswordResetCompleted = "emailpassword:password_reset:completed" )
const ( // ExtraKeyRole represents the user's assigned role during registration (e.g. "admin", "user"). ExtraKeyRole = "role" // ExtraKeyOrganizationID represents the unique identifier of the organization to assign the user to. ExtraKeyOrganizationID = "organization_id" // ExtraKeyOrgID is a shorthand alias for ExtraKeyOrganizationID. ExtraKeyOrgID = "org_id" // ExtraKeyPhone represents the user's contact phone number. ExtraKeyPhone = "phone" // ExtraKeyPhoneNumber is an alias for ExtraKeyPhone. ExtraKeyPhoneNumber = "phone_number" // ExtraKeyAvatar represents the avatar image URL for the newly registered user. ExtraKeyAvatar = "avatar" // ExtraKeyLocale represents the preferred language/locale code of the user. ExtraKeyLocale = "locale" // ExtraKeyPermissions represents initial permissions assigned to the user. ExtraKeyPermissions = "permissions" // ExtraKeyMetadata represents arbitrary structured user metadata. ExtraKeyMetadata = "metadata" // ExtraKeyIsAnonymous indicates whether the registered account is a temporary/anonymous account. ExtraKeyIsAnonymous = "is_anonymous" )
Standard Extra metadata keys that can be set or consumed during EmailPassword operations (such as in EventSignUpBefore, EventSignUpAfter, and CreateUserParams).
const ( // ContextKeyVerificationTokenPrefix is the prefix used when caching email verification tokens in plugin.Context. ContextKeyVerificationTokenPrefix = "emailpassword:verification_token:" // ContextKeyResetTokenPrefix is the prefix used when caching password reset tokens in plugin.Context. ContextKeyResetTokenPrefix = "emailpassword:reset_token:" )
Shared plugin context keys used for internal state management.
Variables ¶
var ( // ErrPasswordTooShort is returned when a password does not satisfy the configured minimum length requirement. ErrPasswordTooShort = errors.New("emailpassword: password does not meet the minimum length requirement") // ErrInvalidCredentials is returned when email or password verification fails during sign-in. ErrInvalidCredentials = errors.New("emailpassword: invalid credentials") // ErrEmailNotVerified is returned when sign-in is attempted by a user whose email has not been verified, and verification is required. ErrEmailNotVerified = errors.New("emailpassword: email address has not been verified") // ErrInvalidCurrentPass is returned during password change when the provided current password does not match stored credentials. ErrInvalidCurrentPass = errors.New("emailpassword: current password is incorrect") // ErrTokenExpired is returned when attempting to consume a verification or password reset token that has expired. ErrTokenExpired = errors.New("emailpassword: token has expired") )
var ( // ErrUserAlreadyExists is returned when attempting to register an email address that is already associated with an existing user. ErrUserAlreadyExists = errors.New("emailpassword: user already exists") // ErrUserNotFound is returned by repository methods when no user matches the given identifier or email. ErrUserNotFound = errors.New("emailpassword: user not found") // ErrAccountNotFound is returned when an authentication credentials record is not found for the specified user and provider. ErrAccountNotFound = errors.New("emailpassword: credential account not found") // ErrInvalidToken is returned when a password reset or email verification token does not exist in storage. ErrInvalidToken = errors.New("emailpassword: verification token invalid or expired") )
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// MinPasswordLength specifies the minimum acceptable length for user passwords (default: 8).
MinPasswordLength int
// RequireEmailVerification enforces that user.EmailVerified must be true before sign-in succeeds (default: false).
RequireEmailVerification bool
// ResetTokenExpiry specifies the duration for which password reset tokens remain valid (default: 15 minutes).
ResetTokenExpiry time.Duration
}
Config defines the configurable options for the EmailPassword plugin.
type Option ¶
type Option func(*Config)
Option defines a functional option for configuring the EmailPassword plugin.
func WithMinPasswordLength ¶
WithMinPasswordLength sets the minimum required password length during registration and password change operations.
func WithRequireEmailVerification ¶
WithRequireEmailVerification defines whether email verification is strictly required before sign-in succeeds.
func WithResetTokenExpiry ¶
WithResetTokenExpiry sets the validity duration for generated password reset tokens.
type PasswordChangeEventPayload ¶
type PasswordChangeEventPayload struct {
// UserID identifies the user whose password is being modified.
UserID string
}
PasswordChangeEventPayload contains the user identifier for password change lifecycle events.
type PasswordResetCompletedEventPayload ¶
type PasswordResetCompletedEventPayload struct {
// UserID identifies the user whose password was reset.
UserID string
}
PasswordResetCompletedEventPayload contains confirmation details after a password reset has completed.
type PasswordResetRequestedEventPayload ¶
type PasswordResetRequestedEventPayload struct {
// User is the target user entity requesting the reset.
User *entity.User
// Token is the secure random token generated for the password reset request.
Token string
// ExpiresAt specifies the exact expiration time for the reset token.
ExpiresAt time.Time
}
PasswordResetRequestedEventPayload contains details required to dispatch a password reset email to a user.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements the modular authentication Plugin interface for credential-based email and password workflows.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New creates and initializes a new EmailPassword plugin instance with the specified repository and functional options.
Arguments:
- repo: Implementation of emailpassword.Repository interface.
- opts: Optional functional configuration options (WithMinPasswordLength, WithRequireEmailVerification, WithResetTokenExpiry).
Returns:
- *Plugin: The configured EmailPassword plugin instance ready for registration in auth.New.
func (*Plugin) ChangePassword ¶
ChangePassword updates an existing authenticated user's password after verifying their current password.
Brief Explanation:
Verifies the current password against stored credentials to prevent unauthorized modification, enforces password length requirements, computes the new password hash, updates the database, and emits EventPasswordChangeBefore and EventPasswordChangeAfter.
Function:
User settings and self-service password update workflow.
Arguments:
- ctx: Request cancellation context.
- input: dto.ChangePasswordParams containing:
- UserID (string, required): Authenticated user's unique identifier.
- CurrentPassword (string, required): Current password for authorization.
- NewPassword (string, required): New password to set.
Returns:
- error: ErrPasswordTooShort, ErrAccountNotFound, ErrInvalidCurrentPass, or database error.
Example:
err := epPlugin.ChangePassword(ctx, dto.ChangePasswordParams{
UserID: "usr_12345",
CurrentPassword: "OldPassword123!",
NewPassword: "NewBrandPassword456!",
})
if err != nil {
log.Fatalf("Password change failed: %v", err)
}
func (*Plugin) ForgotPassword ¶
func (p *Plugin) ForgotPassword(ctx context.Context, input dto.ForgotPasswordParams) (*entity.VerificationToken, error)
ForgotPassword initiates a tokenized password recovery workflow for a user.
Brief Explanation:
Finds the user by email, generates a 32-byte cryptographically secure random token, persists the token with an expiration timestamp, and publishes EventPasswordResetRequested so email/notification dispatchers can send the recovery link to the user.
Function:
Initial step of forgot-password and account recovery.
Arguments:
- ctx: Request cancellation context.
- input: dto.ForgotPasswordParams containing:
- Email (string, required): User email address requesting reset.
Returns:
- *entity.VerificationToken: The generated verification token entity (containing Token string and ExpiresAt).
- error: ErrUserNotFound or database error.
Example:
token, err := epPlugin.ForgotPassword(ctx, dto.ForgotPasswordParams{
Email: "john.doe@example.com",
})
if err != nil {
log.Fatalf("Forgot password failed: %v", err)
}
fmt.Printf("Reset link token: %s (expires: %v)\n", token.Token, token.ExpiresAt)
func (*Plugin) ResetPassword ¶
ResetPassword completes a password reset by consuming a single-use token and setting a new password.
Brief Explanation:
Validates token existence and expiry, hashes the new password, updates the user's credential account, atomically deletes the consumed token to guarantee single-use safety, and emits EventPasswordResetCompleted.
Function:
Final step of forgot-password and recovery verification.
Arguments:
- ctx: Request cancellation context.
- input: dto.ResetPasswordParams containing:
- Token (string, required): Single-use recovery token from email.
- NewPassword (string, required): New password to set.
Returns:
- error: ErrPasswordTooShort, ErrInvalidToken, ErrTokenExpired, ErrUserNotFound, or database error.
Example:
err := epPlugin.ResetPassword(ctx, dto.ResetPasswordParams{
Token: "9a8b7c6d5e4f3a2b1c0d",
NewPassword: "BrandNewSecurePassword123!",
})
if err != nil {
log.Fatalf("Password reset failed: %v", err)
}
func (*Plugin) SignIn ¶
SignIn authenticates user credentials by verifying email existence and comparing the password hash.
Brief Explanation:
Fetches the user and corresponding credentials account, securely verifies the password using constant-time comparison, checks email verification prerequisites (if configured), and publishes EventSignInBefore and EventSignInAfter.
Function:
Primary entry point for user login authentication.
Arguments:
- ctx: Request cancellation context.
- input: dto.SignInParams containing:
- Email (string, required): User email address.
- Password (string, required): Plaintext password to compare against stored hash.
Returns:
- *entity.User: The authenticated user profile.
- error: ErrInvalidCredentials, ErrEmailNotVerified, or database error.
Example:
user, err := epPlugin.SignIn(ctx, dto.SignInParams{
Email: "john.doe@example.com",
Password: "SuperSecretPassword123!",
})
if err != nil {
log.Fatalf("Authentication failed: %v", err)
}
func (*Plugin) SignUp ¶
SignUp registers a new user with email and password credentials.
Brief Explanation:
Validates password constraints, ensures email uniqueness, securely hashes the password using bcrypt/argon2, publishes the EventSignUpBefore event (enabling listeners to mutate parameters or inject dynamic metadata), persists both the user entity and credential account, and finally publishes EventSignUpAfter.
Function:
Primary entry point for user registration.
Arguments:
- ctx: Request cancellation context.
- input: dto.SignUpParams containing:
- Email (string, required): User's primary email address.
- Password (string, required): Plaintext password to hash and validate.
- Name (string, optional): Display name of the user.
- Extra (map[string]any, optional): Dynamic metadata (e.g. role, organization, phone).
Returns:
- *entity.User: The persisted user entity containing generated ID and timestamps.
- error: ErrPasswordTooShort, ErrUserAlreadyExists, or database error.
Example:
user, err := epPlugin.SignUp(ctx, dto.SignUpParams{
Email: "john.doe@example.com",
Password: "SuperSecretPassword123!",
Name: "John Doe",
})
if err != nil {
log.Fatalf("Sign up failed: %v", err)
}
fmt.Printf("Created user with ID: %s\n", user.ID)
type Repository ¶
type Repository interface {
// GetUserByEmail retrieves a user entity matching the provided unique email address.
//
// Function:
// Used during Sign-In and Forgot-Password to check user existence and retrieve profile details.
//
// Arguments:
// - ctx: Request cancellation context.
// - email: The normalized email address to query.
//
// Returns:
// - *entity.User: The matching user entity if found.
// - error: ErrUserNotFound if no user matches, or database failure error.
//
// Example SQL:
// SELECT id, email, name, email_verified, created_at, updated_at FROM users WHERE email = $1 LIMIT 1;
GetUserByEmail(ctx context.Context, email string) (*entity.User, error)
// GetUserByID retrieves a user entity matching the given unique identifier.
//
// Function:
// Used during Change-Password and Reset-Password verification flows.
//
// Arguments:
// - ctx: Request cancellation context.
// - id: The unique primary key identifier of the user (e.g. UUID).
//
// Returns:
// - *entity.User: The matching user entity.
// - error: ErrUserNotFound if no record matches, or database failure error.
//
// Example SQL:
// SELECT id, email, name, email_verified, created_at, updated_at FROM users WHERE id = $1 LIMIT 1;
GetUserByID(ctx context.Context, id string) (*entity.User, error)
// CreateUser persists a new user record generated from the provided registration parameters.
//
// Function:
// Called during SignUp to create the primary user entity. Plugins may inspect or modify
// params.Extra before this method is called via EventSignUpBefore.
//
// Arguments:
// - ctx: Request cancellation context.
// - params: Pointer to CreateUserParams containing Email, Name, PasswordHash, and Extra metadata.
//
// Returns:
// - *entity.User: The newly created user entity with populated ID and timestamps.
// - error: ErrUserAlreadyExists on unique violation, or database failure error.
//
// Example SQL:
// INSERT INTO users (id, email, name, password_hash, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6);
CreateUser(ctx context.Context, params *dto.CreateUserParams) (*entity.User, error)
// UpdateUser updates an existing user profile record in storage.
//
// Function:
// Used when updating user metadata, email verification state, or profile attributes.
//
// Arguments:
// - ctx: Request cancellation context.
// - user: The updated user entity.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// UPDATE users SET email = $1, name = $2, email_verified = $3, updated_at = $4 WHERE id = $5;
UpdateUser(ctx context.Context, user *entity.User) error
// GetAccountByUserIDAndProvider retrieves the credential account associated with a user and authentication provider.
//
// Function:
// Used during SignIn and ChangePassword to retrieve stored hashed passwords (provider: "credential").
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: The target user's ID.
// - provider: The authentication provider identifier (typically "credential").
//
// Returns:
// - *entity.Account: The matching credentials account containing the password hash.
// - error: ErrAccountNotFound if no record matches, or database failure error.
//
// Example SQL:
// SELECT id, user_id, provider, password, created_at FROM accounts WHERE user_id = $1 AND provider = $2 LIMIT 1;
GetAccountByUserIDAndProvider(ctx context.Context, userID, provider string) (*entity.Account, error)
// CreateAccount persists a new provider credentials record associated with a user.
//
// Function:
// Called immediately after CreateUser during SignUp to link credential passwords to the user.
//
// Arguments:
// - ctx: Request cancellation context.
// - account: The credentials account entity to insert.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// INSERT INTO accounts (id, user_id, provider, password, created_at) VALUES ($1, $2, $3, $4, $5);
CreateAccount(ctx context.Context, account *entity.Account) error
// UpdateAccountPassword updates the hashed password for a specific account record.
//
// Function:
// Called during ChangePassword and ResetPassword to overwrite the stored password hash.
//
// Arguments:
// - ctx: Request cancellation context.
// - accountID: Primary key ID of the account record to update.
// - hashedPassword: The newly computed bcrypt/argon2 password hash.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// UPDATE accounts SET password = $1 WHERE id = $2;
UpdateAccountPassword(ctx context.Context, accountID, hashedPassword string) error
// CreateVerificationToken persists a short-lived token record for password resets or email confirmations.
//
// Function:
// Called during ForgotPassword to save the generated reset token and expiration timestamp.
//
// Arguments:
// - ctx: Request cancellation context.
// - token: The VerificationToken entity (Identifier/Email, Token, ExpiresAt).
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// INSERT INTO verification_tokens (identifier, token, expires_at) VALUES ($1, $2, $3);
CreateVerificationToken(ctx context.Context, token *entity.VerificationToken) error
// GetVerificationToken retrieves an active token record by its token string.
//
// Function:
// Called during ResetPassword to validate token existence and verify whether it has expired.
//
// Arguments:
// - ctx: Request cancellation context.
// - token: The raw token string submitted by the user.
//
// Returns:
// - *entity.VerificationToken: The matching token entity with its expiration timestamp.
// - error: ErrInvalidToken if no record is found, or database failure error.
//
// Example SQL:
// SELECT identifier, token, expires_at FROM verification_tokens WHERE token = $1 LIMIT 1;
GetVerificationToken(ctx context.Context, token string) (*entity.VerificationToken, error)
// DeleteVerificationToken removes a consumed or invalidated token from storage.
//
// Function:
// Called immediately upon successful password reset to guarantee single-use token consumption.
//
// Arguments:
// - ctx: Request cancellation context.
// - token: The token string to delete.
//
// Returns:
// - error: Nil on success, or database error on failure.
//
// Example SQL:
// DELETE FROM verification_tokens WHERE token = $1;
DeleteVerificationToken(ctx context.Context, token string) error
}
Repository defines the persistent storage contract required by the EmailPassword plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, MongoDB, GORM).
Implementation Example (GORM / database/sql): ¶
type GormAuthRepository struct {
db *gorm.DB
}
func (r *GormAuthRepository) GetUserByEmail(ctx context.Context, email string) (*entity.User, error) {
var m UserModel
if err := r.db.WithContext(ctx).Where("email = ?", email).First(&m).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, emailpassword.ErrUserNotFound
}
return nil, err
}
return m.ToEntity(), nil
}
func (r *GormAuthRepository) CreateUser(ctx context.Context, params *dto.CreateUserParams) (*entity.User, error) {
m := UserModel{
ID: uuid.NewString(),
Email: params.Email,
Name: params.Name,
PasswordHash: params.PasswordHash,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := r.db.WithContext(ctx).Create(&m).Error; err != nil {
return nil, err
}
return m.ToEntity(), nil
}
type SignInEventPayload ¶
SignInEventPayload contains the authenticated user entity associated with a sign-in event.
type SignUpEventPayload ¶
type SignUpEventPayload struct {
// Params holds mutable user creation parameters (including dynamic Extra metadata).
Params *dto.CreateUserParams
// User contains the persisted user entity (populated in EventSignUpAfter).
User *entity.User
}
SignUpEventPayload contains the parameter and entity data associated with a sign-up event.