Local authentication
The auth/local package separates password verification from application persistence. Your application implements CredentialStore, which returns a user and a bcrypt password hash for an account; the appkit service verifies the password and starts a session.
Implement the credential store
Return auth.ErrInvalidCredentials when the account is unknown or disabled. Do not reveal whether a username exists.
type credentialStore struct {
db *sql.DB
}
func (s credentialStore) LookupCredential(
ctx context.Context,
username string,
) (User, string, error) {
// Load the application user and bcrypt hash from your database.
// Return auth.ErrInvalidCredentials for absent or disabled accounts.
}
Sign in and issue a session
service := local.Service[User]{
Credentials: credentialStore{db: db},
Sessions: sessions,
}
user, token, err := service.SignIn(r.Context(), form.Username, form.Password)
if err != nil {
return err
}
http.SetCookie(w, cookieConfig.Cookie(token, false))
SignIn trims the username, maps missing or rejected credentials to auth.ErrInvalidCredentials, verifies the bcrypt hash, and returns a newly generated opaque session token. Store the token only in the browser cookie; session persistence receives a hash, as described in the sessions guide.
Password lifecycle
Create new hashes with local.HashPassword. Apply your own rules—minimum length, breach screening, MFA requirements, account lockout, and password-reset flow—before storing or accepting a password. Appkit intentionally does not prescribe those domain policies.