Documentation
¶
Index ¶
- func LinkLocalCredentials(config EnsureAuthUserConfig, userID string, username, password, email string) error
- func NewCreateUserFunc(userStore core.UserStore, identityStore core.IdentityStore, ...) core.CreateUserFunc
- func NewCredentialsValidator(identityStore core.IdentityStore, channelStore core.ChannelStore, ...) core.CredentialsValidator
- func NewCredentialsValidatorWithUsername(identityStore core.IdentityStore, channelStore core.ChannelStore, ...) core.CredentialsValidator
- func NewEnsureAuthUserFunc(config EnsureAuthUserConfig) ...
- type EnsureAuthUserConfig
- type GetLoggedInUserFunc
- type LinkCredentialsConfig
- 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 UpdatePasswordFunc
- type VerifyEmailFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LinkLocalCredentials ¶
func LinkLocalCredentials(config EnsureAuthUserConfig, 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
Example Handler in Your App ¶
func handleSetPassword(w http.ResponseWriter, r *http.Request) {
userID := getLoggedInUserID(r) // from session/JWT
user, _ := userStore.GetUserById(userID)
email := user.Profile()["email"].(string)
username := r.FormValue("username") // optional
password := r.FormValue("password")
err := oneauth.LinkLocalCredentials(config, userID, username, password, email)
if err != nil {
// handle error (e.g., username taken, password too weak)
}
// redirect to profile with success message
}
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"
func NewCreateUserFunc ¶
func NewCreateUserFunc(userStore core.UserStore, identityStore core.IdentityStore, channelStore core.ChannelStore) core.CreateUserFunc
NewCreateUserFunc creates a CreateUserFunc from stores
func NewCredentialsValidator ¶
func NewCredentialsValidator(identityStore core.IdentityStore, channelStore core.ChannelStore, userStore core.UserStore) core.CredentialsValidator
NewCredentialsValidator creates a CredentialsValidator from stores
func NewCredentialsValidatorWithUsername ¶
func NewCredentialsValidatorWithUsername(identityStore core.IdentityStore, channelStore core.ChannelStore, userStore core.UserStore, usernameStore core.UsernameStore) core.CredentialsValidator
NewCredentialsValidatorWithUsername creates a CredentialsValidator that supports logging in with username (in addition to email/phone).
Who Calls This ¶
Use this instead of NewCredentialsValidator when setting up LocalAuth if you want users to be able to login with their username:
localAuth := &oneauth.LocalAuth{
ValidateCredentials: oneauth.NewCredentialsValidatorWithUsername(
identityStore, channelStore, userStore, usernameStore,
),
// ... other config
}
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).
func NewEnsureAuthUserFunc ¶
func NewEnsureAuthUserFunc(config EnsureAuthUserConfig) func(authtype string, provider string, token any, userInfo map[string]any) (core.User, error)
NewEnsureAuthUserFunc creates a function that handles user creation/lookup for both OAuth and local authentication with channel linking support.
Who Calls This ¶
This function is called by OneAuth.SaveUserAndRedirect after a successful OAuth callback or local login. The returned function implements the core logic for AuthUserStore.EnsureAuthUser.
Flow for OAuth (e.g., Google Login) ¶
- User clicks "Login with Google" → redirects to Google
- Google redirects back to /auth/google/callback with auth code
- OAuth handler exchanges code for token, fetches userInfo (email, name, picture)
- OAuth handler calls OneAuth.SaveUserAndRedirect(authtype="oauth", provider="google", token, userInfo)
- SaveUserAndRedirect calls UserStore.EnsureAuthUser → this function
- This function checks if email identity exists: - EXISTS: Link Google channel to existing user, update profile["channels"] - NEW: Create User, Identity (verified=true), Google Channel
- SaveUserAndRedirect creates JWT, sets cookies, redirects to app
Flow for Local Signup ¶
- User submits signup form with email/password
- LocalAuth.HandleSignup validates and calls CreateUser (from NewCreateUserFunc)
- CreateUser creates User, Identity (verified=false), Local Channel
- HandleSignup calls HandleUser → SaveUserAndRedirect → this function
- User is logged in (or email verification required)
Channel Linking Logic ¶
Multiple channels (local, google, github) can point to the same user via shared email:
User (id: abc123) ├── Identity: email → user@example.com ├── Channel: local → email:user@example.com (password_hash) ├── Channel: google → email:user@example.com (oauth profile) └── Channel: github → email:user@example.com (oauth profile)
User profile tracks linked providers: profile["channels"] = ["local", "google", "github"]
Types ¶
type EnsureAuthUserConfig ¶
type EnsureAuthUserConfig struct {
UserStore core.UserStore
IdentityStore core.IdentityStore
ChannelStore core.ChannelStore
UsernameStore core.UsernameStore // Optional - for username uniqueness
}
EnsureAuthUserConfig holds configuration for NewEnsureAuthUserFunc.
Example setup in your app:
config := oneauth.EnsureAuthUserConfig{
UserStore: gaeStores.UserStore,
IdentityStore: gaeStores.IdentityStore,
ChannelStore: gaeStores.ChannelStore,
UsernameStore: gaeStores.UsernameStore, // optional
}
ensureUser := oneauth.NewEnsureAuthUserFunc(config)
// Then use with OneAuth:
authUserStore := &MyAuthUserStore{config: config, ensureUser: ensureUser}
oneAuth.UserStore = authUserStore
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 core.UserStore
IdentityStore core.IdentityStore
ChannelStore core.ChannelStore
UsernameStore core.UsernameStore // Optional
}
LinkCredentialsConfig holds configuration for HandleLinkCredentials
type LocalAuth ¶
type LocalAuth struct {
// Validates credentials during login
ValidateCredentials core.CredentialsValidator
// Validates credentials during signup (deprecated: use SignupPolicy instead)
ValidateSignup core.SignupValidator
// Creates a new user (for signup)
CreateUser core.CreateUserFunc
// Optional email sender for verification emails
EmailSender core.SendEmail
// Optional token store for email verification and password reset
TokenStore core.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 core.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 *core.SignupPolicy
// OnSignupError is called when signup fails. If nil, returns JSON error.
OnSignupError core.AuthErrorHandler
// OnLoginError is called when login fails. If nil, returns JSON error.
OnLoginError core.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 core.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 UpdatePasswordFunc ¶
func NewUpdatePasswordFunc ¶
func NewUpdatePasswordFunc(identityStore core.IdentityStore, channelStore core.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 VerifyEmailFunc ¶
func NewVerifyEmailFunc ¶
func NewVerifyEmailFunc(identityStore core.IdentityStore, tokenStore core.TokenStore) VerifyEmailFunc
NewVerifyEmailFunc creates a VerifyEmailFunc from stores