Documentation
¶
Index ¶
- Constants
- Variables
- func DetectUsernameType(username string) string
- func LinkLocalCredentials(config LinkLocalCredentialsConfig, userID string, ...) error
- type ConsoleEmailSender
- type CreateUserFunc
- type Credentials
- type CredentialsValidator
- type GetLoggedInUserFunc
- type LinkCredentialsConfig
- type LinkLocalCredentialsConfig
- type LocalAuth
- func (a *LocalAuth) HandleForgotPassword(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) HandleForgotPasswordForm(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) HandleLinkCredentials(config LinkCredentialsConfig, getUser GetLoggedInUserFunc) http.HandlerFunc
- func (a *LocalAuth) HandleResetPassword(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) HandleResetPasswordForm(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) HandleSignup(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) HandleVerifyEmail(w http.ResponseWriter, r *http.Request)
- func (a *LocalAuth) ServeHTTP(w http.ResponseWriter, r *http.Request)
- type SendEmail
- type SignupPolicy
- type SignupValidator
- type UpdatePasswordFunc
- type VerificationToken
- type VerificationTokenStore
- type VerificationType
- type VerifyEmailFunc
Constants ¶
const ( VerificationExpiryEmail = 24 * time.Hour VerificationExpiryPasswordReset = 1 * time.Hour )
Default verification token expiry durations.
Variables ¶
var PolicyEmailOnly = SignupPolicy{ RequireUsername: false, RequireEmail: true, RequirePhone: false, RequirePassword: true, EnforceUsernameUnique: true, EnforceEmailUnique: true, MinPasswordLength: 8, UsernamePattern: `^[a-zA-Z0-9_-]{3,20}$`, }
PolicyEmailOnly requires only email and password for signup (username optional).
var PolicyFlexible = SignupPolicy{ RequireUsername: false, RequireEmail: false, RequirePhone: false, RequirePassword: false, EnforceUsernameUnique: true, EnforceEmailUnique: true, MinPasswordLength: 8, UsernamePattern: `^[a-zA-Z0-9_-]{3,20}$`, }
PolicyFlexible is OAuth-friendly — email/phone optional, username optional.
var PolicyUsernameRequired = SignupPolicy{ RequireUsername: true, RequireEmail: true, RequirePhone: false, RequirePassword: true, EnforceUsernameUnique: true, EnforceEmailUnique: true, MinPasswordLength: 8, UsernamePattern: `^[a-zA-Z0-9_-]{3,20}$`, }
PolicyUsernameRequired requires username, email, and password for signup.
Functions ¶
func DetectUsernameType ¶ added in v0.1.0
DetectUsernameType is re-exported from accounts so callers that import localauth don't need a second import for this widely-used helper.
func LinkLocalCredentials ¶
func LinkLocalCredentials(config LinkLocalCredentialsConfig, userID string, username, password, email string) error
LinkLocalCredentials adds local (password) authentication to an existing OAuth-only user. This enables "incremental auth" where users sign up via OAuth and later add a password.
Who Calls This ¶
Your app calls this from a "Set Password" or "Complete Profile" page. Typically:
- User signed up via Google OAuth (has google channel, no local channel)
- User visits profile page, sees "Add password for email login"
- User submits password (and optionally username) form
- Your handler calls LinkLocalCredentials with the logged-in user's ID
- User can now login with email/password OR Google
What It Does ¶
- Verifies the email belongs to the given userID
- Checks that local channel doesn't already exist
- Creates local channel with hashed password
- Reserves username in UsernameStore (if configured and username provided)
- Updates user profile["channels"] to include "local"
Types ¶
type ConsoleEmailSender ¶ added in v0.1.0
type ConsoleEmailSender struct{}
ConsoleEmailSender is a development implementation that logs emails to console.
func (*ConsoleEmailSender) SendPasswordResetEmail ¶ added in v0.1.0
func (c *ConsoleEmailSender) SendPasswordResetEmail(to string, resetLink string) error
func (*ConsoleEmailSender) SendVerificationEmail ¶ added in v0.1.0
func (c *ConsoleEmailSender) SendVerificationEmail(to string, verificationLink string) error
type CreateUserFunc ¶ added in v0.1.0
type CreateUserFunc func(creds *Credentials) (accounts.User, error)
CreateUserFunc creates a new user with the given credentials.
func NewCreateUserFunc ¶
func NewCreateUserFunc(userStore accounts.UserStore, identityStore accounts.IdentityStore, channelStore accounts.ChannelStore) CreateUserFunc
NewCreateUserFunc creates a CreateUserFunc from stores.
type Credentials ¶ added in v0.1.0
type Credentials struct {
Username string // Required for signup, can be username/email/phone for login
Email *string // Optional for signup
Phone *string // Optional for signup
Password string // Required
}
Credentials represents user credentials for signup or login.
type CredentialsValidator ¶ added in v0.1.0
type CredentialsValidator = accounts.CredentialsValidator
CredentialsValidator is the same shape as accounts.CredentialsValidator — type-aliased here so existing localauth callers don't have to switch imports.
func NewCredentialsValidator ¶
func NewCredentialsValidator(identityStore accounts.IdentityStore, channelStore accounts.ChannelStore, userStore accounts.UserStore) CredentialsValidator
NewCredentialsValidator creates a CredentialsValidator from stores.
func NewCredentialsValidatorWithUsername ¶
func NewCredentialsValidatorWithUsername(identityStore accounts.IdentityStore, channelStore accounts.ChannelStore, userStore accounts.UserStore, usernameStore accounts.UsernameStore) CredentialsValidator
NewCredentialsValidatorWithUsername creates a CredentialsValidator that supports logging in with username (in addition to email/phone).
How Username Login Works ¶
- User enters "johndoe" and password on login form
- DetectUsernameType returns "username" (not email, not phone)
- This validator looks up "johndoe" in UsernameStore → gets userID
- Gets user's email identity from IdentityStore
- Gets local channel for that email identity
- Verifies password against channel's password_hash
- Returns the user
Fallback Behavior ¶
If user enters an email or phone number instead of username, it falls back to the standard email/phone lookup (same as NewCredentialsValidator).
type GetLoggedInUserFunc ¶
GetLoggedInUserFunc returns the currently logged-in user ID from the request. Apps must implement this based on their session/JWT handling.
type LinkCredentialsConfig ¶
type LinkCredentialsConfig struct {
UserStore accounts.UserStore
IdentityStore accounts.IdentityStore
ChannelStore accounts.ChannelStore
UsernameStore accounts.UsernameStore // Optional
}
LinkCredentialsConfig holds configuration for HandleLinkCredentials.
type LinkLocalCredentialsConfig ¶ added in v0.1.0
type LinkLocalCredentialsConfig struct {
UserStore accounts.UserStore
IdentityStore accounts.IdentityStore
ChannelStore accounts.ChannelStore
UsernameStore accounts.UsernameStore // Optional — reserves the username if set
}
LinkLocalCredentialsConfig groups the stores LinkLocalCredentials needs. Self-contained so localauth doesn't have to import federatedauth just for the cross-cutting "add local password to an OAuth user" flow.
type LocalAuth ¶
type LocalAuth struct {
// Validates credentials during login
ValidateCredentials CredentialsValidator
// Validates credentials during signup (deprecated: use SignupPolicy instead)
ValidateSignup SignupValidator
// Creates a new user (for signup)
CreateUser CreateUserFunc
// Optional email sender for verification emails
EmailSender SendEmail
// Optional token store for email verification and password reset
TokenStore VerificationTokenStore
// Base URL for generating verification/reset links
BaseURL string
// Whether email verification is required before login
RequireEmailVerification bool
// Provider name (defaults to "local")
Provider string
// Form field names
UsernameField string
PasswordField string
EmailField string
PhoneField string
// Handler called after successful authentication
HandleUser accounts.HandleUserFunc
// Callback to verify email by token
VerifyEmail VerifyEmailFunc
// Callback to update password
UpdatePassword UpdatePasswordFunc
// SignupPolicy defines what is required for signup (overrides ValidateSignup if set)
SignupPolicy *SignupPolicy
// OnSignupError is called when signup fails. If nil, returns JSON error.
OnSignupError accounts.AuthErrorHandler
// OnLoginError is called when login fails. If nil, returns JSON error.
OnLoginError accounts.AuthErrorHandler
// SignupURL is used for redirects on error (if OnSignupError uses redirects)
SignupURL string
// LoginURL is used for redirects on error (if OnLoginError uses redirects)
LoginURL string
// Optional UsernameStore for enforcing username uniqueness
UsernameStore accounts.UsernameStore
// ForgotPasswordURL: if set, GET /forgot-password redirects here and
// POST /forgot-password redirects here with ?sent=true on success.
// If empty, GET renders a basic HTML form and POST returns JSON.
ForgotPasswordURL string
// ResetPasswordURL: if set, GET /reset-password redirects here (with ?token=...)
// and POST redirects here with ?success=true on success or ?error=... on failure.
// If empty, GET renders a basic HTML form and POST returns JSON.
ResetPasswordURL string
// RateLimiter limits login attempts per key (IP:username). Optional.
// When set, rate-limited requests receive 429 Too Many Requests.
RateLimiter core.RateLimiter
// Lockout locks accounts after consecutive failed login attempts. Optional.
// When set, locked accounts receive 429 Too Many Requests until the lockout expires.
Lockout *core.AccountLockout
}
Allows local username/password based authentication.
func (*LocalAuth) HandleForgotPassword ¶
func (a *LocalAuth) HandleForgotPassword(w http.ResponseWriter, r *http.Request)
HandleForgotPassword handles forgot password requests (POST)
func (*LocalAuth) HandleForgotPasswordForm ¶
func (a *LocalAuth) HandleForgotPasswordForm(w http.ResponseWriter, r *http.Request)
HandleForgotPasswordForm shows the forgot password form (GET)
func (*LocalAuth) HandleLinkCredentials ¶
func (a *LocalAuth) HandleLinkCredentials(config LinkCredentialsConfig, getUser GetLoggedInUserFunc) http.HandlerFunc
HandleLinkCredentials returns an HTTP handler that adds local (password) auth to an existing OAuth-only user.
Who Calls This ¶
Mount this handler at a protected route (requires login) like POST /auth/link-credentials:
localAuth := &oneauth.LocalAuth{...}
linkConfig := oneauth.LinkCredentialsConfig{
UserStore: stores.UserStore,
IdentityStore: stores.IdentityStore,
ChannelStore: stores.ChannelStore,
UsernameStore: stores.UsernameStore, // optional
}
getUser := func(r *http.Request) (string, error) {
return getLoggedInUserIDFromSession(r), nil
}
mux.Handle("POST /auth/link-credentials", localAuth.HandleLinkCredentials(linkConfig, getUser))
Flow ¶
- OAuth-only user visits profile page, sees "Add password" form
- User submits form with password (and optionally username)
- Handler validates input, creates local channel, reserves username
- User can now login with email/password OR their OAuth provider
Form Fields ¶
- password (required): The new password
- username (optional): Username for login (if UsernameStore configured)
Responses ¶
- 200 OK: {"success": true, "message": "..."}
- 400 Bad Request: {"error": "...", "code": "...", "field": "..."}
- 401 Unauthorized: User not logged in
- 409 Conflict: Local credentials already exist
func (*LocalAuth) HandleResetPassword ¶
func (a *LocalAuth) HandleResetPassword(w http.ResponseWriter, r *http.Request)
HandleResetPassword handles password reset submissions (POST)
func (*LocalAuth) HandleResetPasswordForm ¶
func (a *LocalAuth) HandleResetPasswordForm(w http.ResponseWriter, r *http.Request)
HandleResetPasswordForm shows the reset password form (GET)
func (*LocalAuth) HandleSignup ¶
func (a *LocalAuth) HandleSignup(w http.ResponseWriter, r *http.Request)
HandleSignup processes user registration.
func (*LocalAuth) HandleVerifyEmail ¶
func (a *LocalAuth) HandleVerifyEmail(w http.ResponseWriter, r *http.Request)
HandleVerifyEmail handles email verification via token
type SendEmail ¶ added in v0.1.0
type SendEmail interface {
SendVerificationEmail(to string, verificationLink string) error
SendPasswordResetEmail(to string, resetLink string) error
}
SendEmail lets applications provide their own email-sending implementation for localauth's verification-email and password-reset flows.
type SignupPolicy ¶ added in v0.1.0
type SignupPolicy struct {
RequireUsername bool // Is username required? (default: false)
RequireEmail bool // Is email required? (default: true)
RequirePhone bool // Is phone required? (default: false)
RequirePassword bool // Is password required for local? (default: true)
EnforceUsernameUnique bool // Check UsernameStore? (default: true if username required)
EnforceEmailUnique bool // Check IdentityStore? (default: true)
MinPasswordLength int // Minimum password (default: 8)
UsernamePattern string // Regex for username (default: ^[a-zA-Z0-9_-]{3,20}$)
}
SignupPolicy defines what is required for signup.
func DefaultSignupPolicy ¶ added in v0.1.0
func DefaultSignupPolicy() SignupPolicy
DefaultSignupPolicy returns a sensible default signup policy.
func (SignupPolicy) GetMinPasswordLength ¶ added in v0.1.0
func (p SignupPolicy) GetMinPasswordLength() int
GetMinPasswordLength returns the minimum password length.
func (SignupPolicy) GetUsernamePattern ¶ added in v0.1.0
func (p SignupPolicy) GetUsernamePattern() *regexp.Regexp
GetUsernamePattern returns the compiled username regex pattern.
type SignupValidator ¶ added in v0.1.0
type SignupValidator func(creds *Credentials) error
SignupValidator validates credentials during signup.
var DefaultSignupValidator SignupValidator = func(creds *Credentials) error { if len(creds.Username) < 3 || len(creds.Username) > 20 { return fmt.Errorf("username must be 3-20 characters") } usernameRegex := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) if !usernameRegex.MatchString(creds.Username) { return fmt.Errorf("username can only contain letters, numbers, underscores, and hyphens") } if creds.Email == nil && creds.Phone == nil { return fmt.Errorf("email or phone required") } if creds.Email != nil && *creds.Email != "" { emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`) if !emailRegex.MatchString(*creds.Email) { return fmt.Errorf("invalid email format") } } if creds.Phone != nil && *creds.Phone != "" { cleaned := strings.ReplaceAll(*creds.Phone, "-", "") cleaned = strings.ReplaceAll(cleaned, " ", "") cleaned = strings.ReplaceAll(cleaned, "(", "") cleaned = strings.ReplaceAll(cleaned, ")", "") if len(cleaned) < 10 { return fmt.Errorf("invalid phone number") } } if len(creds.Password) < 8 { return fmt.Errorf("password must be at least 8 characters") } return nil }
DefaultSignupValidator provides sensible default validation for signup.
type UpdatePasswordFunc ¶
func NewUpdatePasswordFunc ¶
func NewUpdatePasswordFunc(identityStore accounts.IdentityStore, channelStore accounts.ChannelStore) UpdatePasswordFunc
NewUpdatePasswordFunc creates an UpdatePasswordFunc from stores. If the user has no local channel (e.g. OAuth-only user), one is created automatically.
type VerificationToken ¶ added in v0.1.0
type VerificationToken struct {
Token string `json:"token"`
Type VerificationType `json:"type"`
UserID string `json:"user_id"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
VerificationToken represents a short-lived email-mediated token used by localauth flows (email verification, password reset).
Renamed from the previous core.AuthToken so the type name reflects its role and doesn't collide with OAuth access/refresh tokens.
func (*VerificationToken) IsExpired ¶ added in v0.1.0
func (t *VerificationToken) IsExpired() bool
IsExpired checks if a verification token has expired.
func (*VerificationToken) IsValid ¶ added in v0.1.0
func (t *VerificationToken) IsValid(expectedType VerificationType) bool
IsValid checks if a token is valid (not expired and matches type).
type VerificationTokenStore ¶ added in v0.1.0
type VerificationTokenStore interface {
CreateToken(userID, email string, tokenType VerificationType, expiryDuration time.Duration) (*VerificationToken, error)
GetToken(token string) (*VerificationToken, error)
DeleteToken(token string) error
DeleteUserTokens(userID string, tokenType VerificationType) error
}
VerificationTokenStore manages localauth verification tokens (signup email-verify, password-reset). Renamed from core.TokenStore.
type VerificationType ¶ added in v0.1.0
type VerificationType string
VerificationType is the kind of email/phone-mediated verification token issued by localauth (e.g. signup email-verify, password-reset).
Renamed from the previous core.TokenType to avoid colliding with OAuth access/refresh-token semantics that live in apiauth/core.
const ( // String values kept stable for backwards-compatible persisted data // across the rename. VerificationTypeEmail VerificationType = "email_verification" VerificationTypePasswordReset VerificationType = "password_reset" )
type VerifyEmailFunc ¶
func NewVerifyEmailFunc ¶
func NewVerifyEmailFunc(identityStore accounts.IdentityStore, tokenStore VerificationTokenStore) VerifyEmailFunc
NewVerifyEmailFunc creates a VerifyEmailFunc from stores.