Documentation
¶
Overview ¶
Package accounts owns the federated end-user account model — the data shape shared by both username/password (localauth) and provider-mediated (federatedauth) authentication flows.
What this package owns:
- User / BasicUser — the account principal as seen by the application
- Identity — a verifiable contact (email, phone) owned by one User
- Channel — per-provider credentials (local, google, github, …)
- UserStore, IdentityStore, ChannelStore, UsernameStore — store interfaces
- AuthError — structured account-level errors used by both flows
What this package deliberately does NOT own:
- OAuth access/refresh tokens, API keys, scopes — see core/
- Username/password specifics (signup policy, credentials shape) — see localauth/
- OAuth/SAML callback orchestration — see federatedauth/
Index ¶
- Constants
- func DetectUsernameType(username string) string
- func IdentityKey(identityType, identityValue string) string
- func LinkedChannels(profile map[string]any) []string
- type AuthError
- type AuthErrorHandler
- type BasicUser
- type ChangeUsernameRequest
- type ChangeUsernameResponse
- type Channel
- type ChannelStore
- type CreateUserRequest
- type CreateUserResponse
- type CredentialsValidator
- type GetChannelRequest
- type GetChannelResponse
- type GetChannelsByIdentityRequest
- type GetChannelsByIdentityResponse
- type GetIdentityRequest
- type GetIdentityResponse
- type GetUserByIDRequest
- type GetUserByIDResponse
- type GetUserByUsernameRequest
- type GetUserByUsernameResponse
- type GetUserIdentitiesRequest
- type GetUserIdentitiesResponse
- type HandleUserFunc
- type Identity
- type IdentityStore
- type MarkIdentityVerifiedRequest
- type MarkIdentityVerifiedResponse
- type ReleaseUsernameRequest
- type ReleaseUsernameResponse
- type ReserveUsernameRequest
- type ReserveUsernameResponse
- type SaveChannelRequest
- type SaveChannelResponse
- type SaveIdentityRequest
- type SaveIdentityResponse
- type SaveUserRequest
- type SaveUserResponse
- type SetUserForIdentityRequest
- type SetUserForIdentityResponse
- type User
- type UserStore
- type UsernameStore
Constants ¶
const ( ErrCodeEmailExists = "email_exists" ErrCodeUsernameTaken = "username_taken" ErrCodeWeakPassword = "weak_password" ErrCodeInvalidUsername = "invalid_username" ErrCodeInvalidEmail = "invalid_email" ErrCodeInvalidPhone = "invalid_phone" ErrCodeMissingField = "missing_field" ErrCodeInvalidCreds = "invalid_credentials" )
Common error codes.
Variables ¶
This section is empty.
Functions ¶
func DetectUsernameType ¶
DetectUsernameType attempts to detect what type of username was provided. Returns "email" if it contains "@", "phone" if it starts with + or a digit, otherwise "username". Used by both localauth's password validator and apiauth's password grant when the host doesn't supply an explicit type.
func IdentityKey ¶
IdentityKey creates a consistent identity key from type and value.
func LinkedChannels ¶
LinkedChannels extracts the channels list from a user profile.
The list is stored under profile["channels"] as either []string or []any (depending on how it was deserialized). Returns an empty slice if the profile is nil or the channels key is missing/of the wrong type.
Types ¶
type AuthError ¶
type AuthError struct {
Code string // "email_exists", "username_taken", "weak_password", "invalid_format", etc.
Message string // Human-readable message
Field string // Which form field has the error (e.g., "email", "username", "password")
}
AuthError represents a structured authentication error surfaced to a user. Used by both local (username/password) and federated (OAuth/SAML) flows when account-level constraints fail — taken email, duplicate username, weak password, etc.
func NewAuthError ¶
NewAuthError creates a new AuthError.
type AuthErrorHandler ¶
AuthErrorHandler is called when authentication errors occur. The handler receives the structured error and should write the response. Returns true if the error was handled (response written), false to use the default JSON response.
Example implementations:
- Redirect back to form with flash message (app uses their session library)
- Redirect with error in query params: /signup?error=email_exists
- Return JSON error response
- Log and show generic error page
type ChangeUsernameRequest ¶ added in v0.1.7
ChangeUsernameRequest is the input to UsernameStore.ChangeUsername.
type ChangeUsernameResponse ¶ added in v0.1.7
type ChangeUsernameResponse struct{}
ChangeUsernameResponse is the output of UsernameStore.ChangeUsername.
type Channel ¶
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"`
ExpiresAt time.Time `json:"expires_at"` // when channel auth expires and needs re-auth
Version int `json:"version"` // optimistic locking version
}
Channel represents an authentication mechanism/provider tied to an Identity.
type ChannelStore ¶
type ChannelStore interface {
// GetChannel gets or optionally creates a channel.
GetChannel(ctx context.Context, req *GetChannelRequest) (*GetChannelResponse, error)
// SaveChannel creates or updates a channel (upsert).
SaveChannel(ctx context.Context, req *SaveChannelRequest) (*SaveChannelResponse, error)
// GetChannelsByIdentity returns all channels for an identity.
GetChannelsByIdentity(ctx context.Context, req *GetChannelsByIdentityRequest) (*GetChannelsByIdentityResponse, error)
}
ChannelStore manages authentication channels/providers.
type CreateUserRequest ¶ added in v0.1.7
CreateUserRequest is the input to UserStore.CreateUser.
type CreateUserResponse ¶ added in v0.1.7
type CreateUserResponse struct {
User User
}
CreateUserResponse wraps the created user.
type CredentialsValidator ¶
CredentialsValidator validates a username/password against the host's user store and returns the corresponding account. Used by both localauth's password login (NewCredentialsValidator returns this shape) and apiauth's password-grant token endpoint.
type GetChannelRequest ¶ added in v0.1.7
GetChannelRequest is the input to ChannelStore.GetChannel.
type GetChannelResponse ¶ added in v0.1.7
GetChannelResponse wraps the looked-up Channel and whether it was newly created in this call.
type GetChannelsByIdentityRequest ¶ added in v0.1.7
type GetChannelsByIdentityRequest struct {
IdentityKey string
}
GetChannelsByIdentityRequest is the input to ChannelStore.GetChannelsByIdentity.
type GetChannelsByIdentityResponse ¶ added in v0.1.7
type GetChannelsByIdentityResponse struct {
Channels []*Channel
}
GetChannelsByIdentityResponse wraps the channels for an identity.
type GetIdentityRequest ¶ added in v0.1.7
GetIdentityRequest is the input to IdentityStore.GetIdentity.
type GetIdentityResponse ¶ added in v0.1.7
GetIdentityResponse wraps the looked-up Identity and whether it was newly created in this call.
type GetUserByIDRequest ¶ added in v0.1.7
type GetUserByIDRequest struct {
UserID string
}
GetUserByIDRequest is the input to UserStore.GetUserById.
type GetUserByIDResponse ¶ added in v0.1.7
type GetUserByIDResponse struct {
User User
}
GetUserByIDResponse wraps the requested user.
type GetUserByUsernameRequest ¶ added in v0.1.7
type GetUserByUsernameRequest struct {
Username string
}
GetUserByUsernameRequest is the input to UsernameStore.GetUserByUsername.
type GetUserByUsernameResponse ¶ added in v0.1.7
type GetUserByUsernameResponse struct {
UserID string
}
GetUserByUsernameResponse wraps the userID for the queried username.
type GetUserIdentitiesRequest ¶ added in v0.1.7
type GetUserIdentitiesRequest struct {
UserID string
}
GetUserIdentitiesRequest is the input to IdentityStore.GetUserIdentities.
type GetUserIdentitiesResponse ¶ added in v0.1.7
type GetUserIdentitiesResponse struct {
Identities []*Identity
}
GetUserIdentitiesResponse wraps the identities owned by the user.
type HandleUserFunc ¶
type HandleUserFunc func(authtype string, provider string, token *oauth2.Token, userInfo map[string]any, w http.ResponseWriter, r *http.Request)
HandleUserFunc is called after successful authentication (OAuth or local) to let the host application complete its session/redirect logic.
type Identity ¶
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"`
UpdatedAt time.Time `json:"updated_at"`
Version int `json:"version"` // optimistic locking version
}
Identity represents a contact method (email, phone) that can be verified.
type IdentityStore ¶
type IdentityStore interface {
// GetIdentity gets or optionally creates an identity.
GetIdentity(ctx context.Context, req *GetIdentityRequest) (*GetIdentityResponse, error)
// SaveIdentity creates or updates an identity (upsert).
SaveIdentity(ctx context.Context, req *SaveIdentityRequest) (*SaveIdentityResponse, error)
// SetUserForIdentity associates an identity with a user.
SetUserForIdentity(ctx context.Context, req *SetUserForIdentityRequest) (*SetUserForIdentityResponse, error)
// MarkIdentityVerified marks an identity as verified.
MarkIdentityVerified(ctx context.Context, req *MarkIdentityVerifiedRequest) (*MarkIdentityVerifiedResponse, error)
// GetUserIdentities returns all identities for a user.
GetUserIdentities(ctx context.Context, req *GetUserIdentitiesRequest) (*GetUserIdentitiesResponse, error)
}
IdentityStore manages contact identities (email, phone).
type MarkIdentityVerifiedRequest ¶ added in v0.1.7
MarkIdentityVerifiedRequest is the input to IdentityStore.MarkIdentityVerified.
type MarkIdentityVerifiedResponse ¶ added in v0.1.7
type MarkIdentityVerifiedResponse struct{}
MarkIdentityVerifiedResponse is the output of IdentityStore.MarkIdentityVerified.
type ReleaseUsernameRequest ¶ added in v0.1.7
type ReleaseUsernameRequest struct {
Username string
}
ReleaseUsernameRequest is the input to UsernameStore.ReleaseUsername.
type ReleaseUsernameResponse ¶ added in v0.1.7
type ReleaseUsernameResponse struct{}
ReleaseUsernameResponse is the output of UsernameStore.ReleaseUsername.
type ReserveUsernameRequest ¶ added in v0.1.7
ReserveUsernameRequest is the input to UsernameStore.ReserveUsername.
type ReserveUsernameResponse ¶ added in v0.1.7
type ReserveUsernameResponse struct{}
ReserveUsernameResponse is the output of UsernameStore.ReserveUsername.
type SaveChannelRequest ¶ added in v0.1.7
type SaveChannelRequest struct {
Channel *Channel
}
SaveChannelRequest is the input to ChannelStore.SaveChannel.
type SaveChannelResponse ¶ added in v0.1.7
type SaveChannelResponse struct{}
SaveChannelResponse is the output of ChannelStore.SaveChannel.
type SaveIdentityRequest ¶ added in v0.1.7
type SaveIdentityRequest struct {
Identity *Identity
}
SaveIdentityRequest is the input to IdentityStore.SaveIdentity.
type SaveIdentityResponse ¶ added in v0.1.7
type SaveIdentityResponse struct{}
SaveIdentityResponse is the output of IdentityStore.SaveIdentity.
type SaveUserRequest ¶ added in v0.1.7
type SaveUserRequest struct {
User User
}
SaveUserRequest is the input to UserStore.SaveUser.
type SaveUserResponse ¶ added in v0.1.7
type SaveUserResponse struct{}
SaveUserResponse is the output of UserStore.SaveUser.
type SetUserForIdentityRequest ¶ added in v0.1.7
SetUserForIdentityRequest is the input to IdentityStore.SetUserForIdentity.
type SetUserForIdentityResponse ¶ added in v0.1.7
type SetUserForIdentityResponse struct{}
SetUserForIdentityResponse is the output of IdentityStore.SetUserForIdentity.
type UserStore ¶
type UserStore interface {
// CreateUser creates a new user with the given ID and profile.
CreateUser(ctx context.Context, req *CreateUserRequest) (*CreateUserResponse, error)
// GetUserById retrieves a user by their ID.
GetUserById(ctx context.Context, req *GetUserByIDRequest) (*GetUserByIDResponse, error)
// SaveUser creates or updates a user (upsert).
SaveUser(ctx context.Context, req *SaveUserRequest) (*SaveUserResponse, error)
}
UserStore manages unified user accounts.
type UsernameStore ¶
type UsernameStore interface {
// ReserveUsername reserves a username for a user (creates username -> userID mapping).
// Returns error if username is already taken.
ReserveUsername(ctx context.Context, req *ReserveUsernameRequest) (*ReserveUsernameResponse, error)
// GetUserByUsername looks up a userID by username.
// Returns error if username not found.
GetUserByUsername(ctx context.Context, req *GetUserByUsernameRequest) (*GetUserByUsernameResponse, error)
// ReleaseUsername removes a username reservation.
ReleaseUsername(ctx context.Context, req *ReleaseUsernameRequest) (*ReleaseUsernameResponse, error)
// ChangeUsername atomically changes a username (release old, reserve new).
// Returns error if new username is already taken.
ChangeUsername(ctx context.Context, req *ChangeUsernameRequest) (*ChangeUsernameResponse, error)
}
UsernameStore manages username uniqueness (optional — for apps that need username-based login).