Documentation
¶
Overview ¶
Package oneauth provides a unified authentication framework for Go applications.
OneAuth separates authentication concerns into three layers: users, identities, and channels. This design enables multiple authentication methods per user while maintaining a single account.
Architecture ¶
User: A unique account in your system. Users are identified by a user ID and contain profile information.
Identity: A contact method (email address or phone number) that belongs to a user. Identities have verification status and can be shared across multiple authentication channels.
Channel: An authentication mechanism (local password, Google OAuth, GitHub OAuth) connected to an identity. Channels store provider-specific credentials and profile data.
Basic Usage ¶
Set up stores for users, identities, channels, and tokens:
import (
"github.com/panyam/oneauth"
"github.com/panyam/oneauth/stores"
)
storagePath := "/path/to/storage"
userStore := stores.NewFSUserStore(storagePath)
identityStore := stores.NewFSIdentityStore(storagePath)
channelStore := stores.NewFSChannelStore(storagePath)
tokenStore := stores.NewFSTokenStore(storagePath)
Create authentication callbacks:
createUser := oneauth.NewCreateUserFunc(userStore, identityStore, channelStore) validateCreds := oneauth.NewCredentialsValidator(identityStore, channelStore, userStore) verifyEmail := oneauth.NewVerifyEmailFunc(identityStore, tokenStore) updatePassword := oneauth.NewUpdatePasswordFunc(identityStore, channelStore)
Configure local authentication:
localAuth := &oneauth.LocalAuth{
CreateUser: createUser,
ValidateCredentials: validateCreds,
EmailSender: &oneauth.ConsoleEmailSender{},
TokenStore: tokenStore,
BaseURL: "https://yourapp.com",
VerifyEmail: verifyEmail,
UpdatePassword: updatePassword,
HandleUser: func(authtype, provider string, token *oauth2.Token,
userInfo map[string]any, w http.ResponseWriter, r *http.Request) {
// Create session and respond
},
}
Set up HTTP handlers:
mux := http.NewServeMux()
mux.Handle("/auth/login", localAuth)
mux.Handle("/auth/signup", http.HandlerFunc(localAuth.HandleSignup))
mux.Handle("/auth/verify-email", http.HandlerFunc(localAuth.HandleVerifyEmail))
mux.Handle("/auth/forgot-password", http.HandlerFunc(localAuth.HandleForgotPassword))
mux.Handle("/auth/reset-password", http.HandlerFunc(localAuth.HandleResetPassword))
Store Implementations ¶
OneAuth provides file-based store implementations in the stores package, suitable for development and small applications. For production use with larger user bases, implement the store interfaces backed by your database.
Security ¶
Passwords are hashed using bcrypt with default cost. Verification and password reset tokens are cryptographically secure 32-byte values, hex-encoded to 64 characters. Tokens expire automatically (24 hours for verification, 1 hour for password reset) and are deleted after single use.
Testing ¶
Authentication handlers can be tested without a running HTTP server using httptest.NewRequest and httptest.ResponseRecorder. Tests use temporary storage directories for complete isolation.
Index ¶
- Constants
- func DetectUsernameType(username string) string
- func GenerateSecureToken() (string, error)
- func IdentityKey(identityType, identityValue string) string
- type AuthToken
- type AuthUserStore
- type BasicUser
- type Channel
- type ChannelStore
- type ConsoleEmailSender
- type CreateUserFunc
- type Credentials
- type CredentialsValidator
- type HandleUserFunc
- type Identity
- type IdentityStore
- 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) 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 Middleware
- type OneAuth
- type SendEmail
- type SignupValidator
- type TokenStore
- type TokenType
- type UpdatePasswordFunc
- type User
- type UserStore
- type VerifyEmailFunc
Constants ¶
const ( TokenExpiryEmailVerification = 24 * time.Hour // 24 hours TokenExpiryPasswordReset = 1 * time.Hour // 1 hour )
Default token expiry durations
Variables ¶
This section is empty.
Functions ¶
func DetectUsernameType ¶ added in v0.0.13
DetectUsernameType attempts to detect what type of username was provided
func GenerateSecureToken ¶ added in v0.0.13
GenerateSecureToken generates a cryptographically secure random token
func IdentityKey ¶ added in v0.0.13
IdentityKey creates a consistent identity key from type and value
Types ¶
type AuthToken ¶ added in v0.0.13
type AuthToken struct {
Token string `json:"token"`
Type TokenType `json:"type"`
UserID string `json:"user_id"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
AuthToken represents a verification or reset token
type AuthUserStore ¶ added in v0.0.13
type AuthUserStore interface {
UserStore
IdentityStore
ChannelStore
// EnsureAuthUser orchestrates user creation/lookup across stores
// This is the main entry point for OAuth and local authentication
EnsureAuthUser(authtype string, provider string, token *oauth2.Token, userInfo map[string]any) (User, error)
}
AuthUserStore combines the store interfaces needed for authentication
type BasicUser ¶
type BasicUser struct {
// contains filtered or unexported fields
}
BasicUser is a simple implementation of the User interface
type Channel ¶ added in v0.0.13
type Channel struct {
Provider string `json:"provider"` // "local", "google", "github"
IdentityKey string `json:"identity_key"` // "email:john@example.com"
Credentials map[string]any `json:"credentials"` // password_hash, access_token, etc.
Profile map[string]any `json:"profile"` // optional data from provider
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Channel represents an authentication mechanism/provider
type ChannelStore ¶ added in v0.0.13
type ChannelStore interface {
// GetChannel gets or optionally creates a channel
GetChannel(provider string, identityKey string, createIfMissing bool) (channel *Channel, newCreated bool, err error)
// SaveChannel creates or updates a channel (upsert)
SaveChannel(channel *Channel) error
// GetChannelsByIdentity returns all channels for an identity
GetChannelsByIdentity(identityKey string) ([]*Channel, error)
}
ChannelStore manages authentication channels/providers
type ConsoleEmailSender ¶ added in v0.0.13
type ConsoleEmailSender struct{}
ConsoleEmailSender is a development implementation that logs emails to console
func (*ConsoleEmailSender) SendPasswordResetEmail ¶ added in v0.0.13
func (c *ConsoleEmailSender) SendPasswordResetEmail(to string, resetLink string) error
func (*ConsoleEmailSender) SendVerificationEmail ¶ added in v0.0.13
func (c *ConsoleEmailSender) SendVerificationEmail(to string, verificationLink string) error
type CreateUserFunc ¶ added in v0.0.13
type CreateUserFunc func(creds *Credentials) (User, error)
CreateUserFunc creates a new user with the given credentials
func NewCreateUserFunc ¶ added in v0.0.13
func NewCreateUserFunc(userStore UserStore, identityStore IdentityStore, channelStore ChannelStore) CreateUserFunc
NewCreateUserFunc creates a CreateUserFunc from stores
type Credentials ¶ added in v0.0.13
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.0.13
CredentialsValidator validates credentials during login and returns the user
func NewCredentialsValidator ¶ added in v0.0.13
func NewCredentialsValidator(identityStore IdentityStore, channelStore ChannelStore, userStore UserStore) CredentialsValidator
NewCredentialsValidator creates a CredentialsValidator from stores
type HandleUserFunc ¶ added in v0.0.9
type Identity ¶ added in v0.0.13
type Identity struct {
Type string `json:"type"` // "email", "phone"
Value string `json:"value"` // "john@example.com", "+1-555-1234"
UserID string `json:"user_id"` // which user owns this identity
Verified bool `json:"verified"` // has any channel verified this identity?
CreatedAt time.Time `json:"created_at"`
}
Identity represents a contact method (email, phone) that can be verified
type IdentityStore ¶ added in v0.0.13
type IdentityStore interface {
// GetIdentity gets or optionally creates an identity
GetIdentity(identityType, identityValue string, createIfMissing bool) (identity *Identity, newCreated bool, err error)
// SaveIdentity creates or updates an identity (upsert)
SaveIdentity(identity *Identity) error
// SetUserForIdentity associates an identity with a user
SetUserForIdentity(identityType, identityValue string, newUserId string) error
// MarkIdentityVerified marks an identity as verified
MarkIdentityVerified(identityType, identityValue string) error
// GetUserIdentities returns all identities for a user
GetUserIdentities(userId string) ([]*Identity, error)
}
IdentityStore manages contact identities (email, phone)
type LocalAuth ¶ added in v0.0.9
type LocalAuth struct {
// Validates credentials during login
ValidateCredentials CredentialsValidator
// Validates credentials during signup
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 TokenStore
// 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 HandleUserFunc
// Callback to verify email by token
VerifyEmail VerifyEmailFunc
// Callback to update password
UpdatePassword UpdatePasswordFunc
}
Allows local username/password based authentication
func (*LocalAuth) HandleForgotPassword ¶ added in v0.0.13
func (a *LocalAuth) HandleForgotPassword(w http.ResponseWriter, r *http.Request)
HandleForgotPassword handles forgot password requests (POST)
func (*LocalAuth) HandleForgotPasswordForm ¶ added in v0.0.13
func (a *LocalAuth) HandleForgotPasswordForm(w http.ResponseWriter, r *http.Request)
HandleForgotPasswordForm shows the forgot password form (GET)
func (*LocalAuth) HandleResetPassword ¶ added in v0.0.13
func (a *LocalAuth) HandleResetPassword(w http.ResponseWriter, r *http.Request)
HandleResetPassword handles password reset submissions (POST)
func (*LocalAuth) HandleResetPasswordForm ¶ added in v0.0.13
func (a *LocalAuth) HandleResetPasswordForm(w http.ResponseWriter, r *http.Request)
HandleResetPasswordForm shows the reset password form (GET)
func (*LocalAuth) HandleSignup ¶ added in v0.0.13
func (a *LocalAuth) HandleSignup(w http.ResponseWriter, r *http.Request)
HandleSignup processes user registration
func (*LocalAuth) HandleVerifyEmail ¶ added in v0.0.13
func (a *LocalAuth) HandleVerifyEmail(w http.ResponseWriter, r *http.Request)
HandleVerifyEmail handles email verification via token
type Middleware ¶
type Middleware struct {
AuthTokenHeaderName string
AuthTokenCookieName string
UserParamName string
CallbackURLParam string
SessionGetter func(r *http.Request, param string) any
GetRedirURL func(r *http.Request) string
DefaultRedirectURL string
VerifyToken func(tokenString string) (loggedInUserId string, token any, err error)
}
func (*Middleware) EnsureReasonableDefaults ¶
func (a *Middleware) EnsureReasonableDefaults()
*
- Ensures that config values have reasonable defaults.
func (*Middleware) EnsureUser ¶
func (a *Middleware) EnsureUser(next http.Handler) http.Handler
func (*Middleware) ExtractUser ¶
func (a *Middleware) ExtractUser(next http.Handler) http.Handler
*
- Fetches the user from the request and loads the UserId and User variables
- available for other handlers. *
- Note this does not perform any redirects if a valid user does not exist.
- To also enforce a user exists, use the EnsureUser handler which both
- calls ExgractUser and ensures that user is logged in.
func (*Middleware) GetLoggedInUserId ¶
func (a *Middleware) GetLoggedInUserId(r *http.Request) string
Get the ID of the logged in user from the current request
type OneAuth ¶
type OneAuth struct {
Session *scs.SessionManager
Middleware Middleware
// Optional name that can be used as a prefix for all required vars
AppName string
// Name of the session variable where the auth token is stored
AuthTokenSessionVar string
// Must be passed in
UserStore AuthUserStore
// All the domains where the auth token cookies will be set on a login success or logout
CookieDomains []string
// JWT related fields
JwtIssuer string
JWTSecretKey string
// How long is a session cookie valid for. Defaults to 1 day
SessionTimeoutInSeconds int
// contains filtered or unexported fields
}
func (*OneAuth) EnsureDefaults ¶
func (*OneAuth) SaveUserAndRedirect ¶
func (a *OneAuth) SaveUserAndRedirect(authtype, provider string, token *oauth2.Token, userInfo map[string]any, w http.ResponseWriter, r *http.Request)
*
- Called by the oauth callback handler with auth token and user info after
- a successful auth flow and redirect. *
- Here is our opportunity to:
- 1. Create a userId that is unique to our system based on userInfo
- 2. Set the right session cookies from this.
type SendEmail ¶ added in v0.0.13
type SendEmail interface {
SendVerificationEmail(to string, verificationLink string) error
SendPasswordResetEmail(to string, resetLink string) error
}
SendEmail interface allows applications to provide their own email sending implementation
type SignupValidator ¶ added in v0.0.13
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 TokenStore ¶ added in v0.0.13
type TokenStore interface {
CreateToken(userID, email string, tokenType TokenType, expiryDuration time.Duration) (*AuthToken, error)
GetToken(token string) (*AuthToken, error)
DeleteToken(token string) error
DeleteUserTokens(userID string, tokenType TokenType) error
}
TokenStore interface for managing auth tokens
type TokenType ¶ added in v0.0.13
type TokenType string
TokenType represents different types of auth tokens
type UpdatePasswordFunc ¶ added in v0.0.13
func NewUpdatePasswordFunc ¶ added in v0.0.13
func NewUpdatePasswordFunc(identityStore IdentityStore, channelStore ChannelStore) UpdatePasswordFunc
NewUpdatePasswordFunc creates an UpdatePasswordFunc from stores
type UserStore ¶
type UserStore interface {
// CreateUser creates a new user with the given ID and profile
CreateUser(userId string, isActive bool, profile map[string]any) (User, error)
// GetUserById retrieves a user by their ID
GetUserById(userId string) (User, error)
// SaveUser creates or updates a user (upsert)
SaveUser(user User) error
}
UserStore manages unified user accounts
type VerifyEmailFunc ¶ added in v0.0.13
func NewVerifyEmailFunc ¶ added in v0.0.13
func NewVerifyEmailFunc(identityStore IdentityStore, tokenStore TokenStore) VerifyEmailFunc
NewVerifyEmailFunc creates a VerifyEmailFunc from stores