Documentation
¶
Overview ¶
Package auth manages local and OIDC accounts, sealed Ed25519 signing keys, five-minute access cookies, thirty-day rotating refresh families and CSRF. Cookie authentication checks the persisted session on every request; password changes and disabled/deleted accounts invalidate access immediately. Refresh secrets and API tokens are persisted only as SHA-256 hashes. Access/refresh lifetimes may be configured through Options. A replay revokes the whole family. Login, refresh and authenticated logout append durable auth-resource events. Failed local logins record only validated attempted account names, never passwords or addresses; backoff/admission denials do not produce audit floods. OIDC failures are attributed only to verified, matching persisted identities. Actor identities include the persisted OIDC issuer and public token metadata, so provider identities and separate API tokens remain distinguishable.
Index ¶
- Constants
- Variables
- func CloneRestrictions(r *domain.TokenRestrictions) *domain.TokenRestrictions
- func HashPassword(password string) (string, error)
- func IsMCPTraffic(ctx context.Context) bool
- func NormalizeRestrictions(r *domain.TokenRestrictions) (*domain.TokenRestrictions, error)
- func RestrictionAllows(r *domain.TokenRestrictions, resource, action, object string) bool
- func RestrictionAllowsOperation(r *domain.TokenRestrictions, resource, action, object string, ...) bool
- func RestrictionsSubset(child, parent *domain.TokenRestrictions) bool
- func ValidatePassword(password string) error
- func VerifyPassword(encoded, password string) bool
- func WithClientIP(ctx context.Context, ip string) context.Context
- func WithMCPTraffic(ctx context.Context) context.Context
- type OIDCSettings
- type Options
- type Principal
- type RateLimitError
- type Service
- func (s *Service) Authenticate(r *http.Request) (*Principal, error)
- func (s *Service) Bootstrap(ctx context.Context, password string) (string, error)
- func (s *Service) ChangePassword(ctx context.Context, name, old, password string) error
- func (s *Service) CreateAccount(ctx context.Context, a domain.Account, password string) (*domain.Account, error)
- func (s *Service) CreateToken(ctx context.Context, owner, name string, expires *time.Time, ...) (string, domain.ApiToken, error)
- func (s *Service) DeleteAccount(ctx context.Context, name string) error
- func (s *Service) DeleteToken(ctx context.Context, id string) error
- func (s *Service) GetAccount(ctx context.Context, name string) (*domain.Account, error)
- func (s *Service) GetToken(ctx context.Context, id string) (*domain.ApiToken, error)
- func (s *Service) ListAccounts(ctx context.Context) ([]domain.Account, error)
- func (s *Service) ListTokens(ctx context.Context, owner string) ([]domain.ApiToken, error)
- func (s *Service) Login(ctx context.Context, w http.ResponseWriter, user, password string) (*SessionInfo, error)
- func (s *Service) LoginHTTP(w http.ResponseWriter, r *http.Request, user, password string) (*SessionInfo, error)
- func (s *Service) Logout(ctx context.Context, w http.ResponseWriter, r *http.Request) error
- func (s *Service) OIDCCallbackHandler(w http.ResponseWriter, r *http.Request)
- func (s *Service) OIDCLoginHandler(w http.ResponseWriter, r *http.Request)
- func (s *Service) RecoverAdmin(ctx context.Context, name, password, masterKey string) (bool, error)
- func (s *Service) Refresh(ctx context.Context, w http.ResponseWriter, r *http.Request) (*SessionInfo, error)
- func (s *Service) ResetPassword(ctx context.Context, name, password string) error
- func (s *Service) Settings(ctx context.Context) (*OIDCSettings, error)
- func (s *Service) UpdateAccount(ctx context.Context, a domain.Account) (*domain.Account, error)
- func (s *Service) UpdateSettings(ctx context.Context, cfg OIDCSettings) error
- func (s *Service) UpdateToken(ctx context.Context, t domain.ApiToken) (*domain.ApiToken, error)
- type SessionInfo
Constants ¶
const ( AccessCookie = "karakoram_access" RefreshCookie = "karakoram_refresh" CSRFCookie = "karakoram_csrf" CSRFHeader = "X-Karakoram-CSRF" )
Cookie names and CSRFHeader are shared with HTTP clients.
Variables ¶
var ErrCSRF = errors.New("invalid CSRF token")
ErrCSRF indicates a missing or mismatched double-submit token.
var ErrInvalid = errors.New("invalid authentication input")
ErrInvalid identifies malformed account, password, token or OIDC input.
var ErrPasswordChangeRequired = errors.New("password change required")
ErrPasswordChangeRequired restricts sessions pending a mandatory change.
var ErrRateLimited = errors.New("login temporarily locked")
ErrRateLimited indicates exponential login backoff is active.
var ErrUnauthenticated = errors.New("invalid credentials or expired authentication")
ErrUnauthenticated deliberately does not disclose account existence.
Functions ¶
func CloneRestrictions ¶ added in v0.3.0
func CloneRestrictions(r *domain.TokenRestrictions) *domain.TokenRestrictions
CloneRestrictions takes an independent authentication snapshot.
func HashPassword ¶
HashPassword uses Argon2id v19, 64 MiB, three iterations, two lanes, a random 16-byte salt and a 32-byte output. Passwords require 12 Unicode characters and are bounded to 1024 bytes to avoid unbounded input processing.
func IsMCPTraffic ¶ added in v0.3.0
IsMCPTraffic reports whether this is a trusted MCP-to-REST dispatch.
func NormalizeRestrictions ¶ added in v0.3.0
func NormalizeRestrictions(r *domain.TokenRestrictions) (*domain.TokenRestrictions, error)
NormalizeRestrictions validates names and the generated permission vocabulary.
func RestrictionAllows ¶ added in v0.3.0
func RestrictionAllows(r *domain.TokenRestrictions, resource, action, object string) bool
RestrictionAllows evaluates the deny overlay; nil preserves legacy authority.
func RestrictionAllowsOperation ¶ added in v0.3.0
func RestrictionAllowsOperation(r *domain.TokenRestrictions, resource, action, object string, collection, secret bool) bool
RestrictionAllowsOperation checks collections without granting global-object access.
func RestrictionsSubset ¶ added in v0.3.0
func RestrictionsSubset(child, parent *domain.TokenRestrictions) bool
RestrictionsSubset rejects any child overlay that could widen the parent's authority.
func ValidatePassword ¶
ValidatePassword enforces the shared local-password policy without hashing.
func VerifyPassword ¶
VerifyPassword checks a bounded supported PHC encoding with constant-time comparison. Parameters from an untrusted hash cannot increase memory or work.
func WithClientIP ¶
WithClientIP attaches the direct peer address to a login context. Forwarded headers must only be used by callers with an explicit trusted-proxy policy.
func WithMCPTraffic ¶ added in v0.3.0
WithMCPTraffic marks a trusted in-process REST dispatch. Network headers cannot set this marker. OAuth authentication may accept MCP-audience tokens only when IsMCPTraffic is true; verified client hosts may later refine the audit suffix.
Types ¶
type OIDCSettings ¶
type OIDCSettings struct {
IssuerURL string `json:"issuerURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret,omitempty"`
Scopes []string `json:"scopes"`
GroupsClaim string `json:"groupsClaim"`
UsernameClaim string `json:"usernameClaim"`
AllowedGroups []string `json:"allowedGroups,omitempty"`
AutoCreate bool `json:"autoCreate"`
}
OIDCSettings configures server-side authorization-code SSO. ClientSecret is write-only: empty on update retains it, and Settings always omits its value.
type Options ¶
type Options struct {
Store *store.Store
Sealer *secrets.Sealer
Issuer string
AccessTTL, RefreshTTL time.Duration
SecureCookies bool
PublicURL string
Logger *slog.Logger
}
Options configures persisted authentication and externally visible URLs.
type Principal ¶
type Principal struct {
Account string
AccountCreatedAt time.Time
Subjects []string
Via string
MustChangePassword bool
TokenID string
TokenName string
OIDCIssuer string
CSRFToken string
Restrictions *domain.TokenRestrictions
}
Principal is the authenticated identity used by policy enforcement.
type RateLimitError ¶
type RateLimitError struct {
RetryAfterSeconds int
}
RateLimitError carries a secret-independent retry delay for login admission.
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
func (*RateLimitError) Unwrap ¶
func (e *RateLimitError) Unwrap() error
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service owns signing keys and serializes identity/session lifecycle changes.
func (*Service) Authenticate ¶
Authenticate accepts a bearer API token, otherwise validates access cookies, persisted session state, account lifecycle and CSRF on unsafe methods.
func (*Service) Bootstrap ¶
Bootstrap creates the initial administrator once and returns only a generated password. Supplied passwords are never returned; every initial admin must change.
func (*Service) ChangePassword ¶
ChangePassword requires the current local password and invalidates old tokens.
func (*Service) CreateAccount ¶
func (s *Service) CreateAccount(ctx context.Context, a domain.Account, password string) (*domain.Account, error)
CreateAccount creates a local-password identity; OIDC identities are only provisioned by verified callbacks.
func (*Service) CreateToken ¶
func (s *Service) CreateToken(ctx context.Context, owner, name string, expires *time.Time, restrictions *domain.TokenRestrictions) (string, domain.ApiToken, error)
CreateToken issues a kk_-prefixed secret exactly once.
func (*Service) DeleteAccount ¶
DeleteAccount removes the owner and all of its persisted sessions and tokens. The account is removed first so partial cleanup still fails authentication closed.
func (*Service) DeleteToken ¶
DeleteToken revokes an API token immediately.
func (*Service) GetAccount ¶
GetAccount returns a credential-free account.
func (*Service) ListAccounts ¶
ListAccounts returns accounts without credentials or provider identity keys.
func (*Service) ListTokens ¶
ListTokens returns metadata, optionally restricted to one owner.
func (*Service) Login ¶
func (s *Service) Login(ctx context.Context, w http.ResponseWriter, user, password string) (*SessionInfo, error)
Login applies account+IP exponential backoff and issues the local session. After five failures delay starts at one second and doubles to fifteen minutes.
func (*Service) LoginHTTP ¶
func (s *Service) LoginHTTP(w http.ResponseWriter, r *http.Request, user, password string) (*SessionInfo, error)
LoginHTTP derives the rate-limit address from RemoteAddr, never proxy headers.
func (*Service) OIDCCallbackHandler ¶
func (s *Service) OIDCCallbackHandler(w http.ResponseWriter, r *http.Request)
OIDCCallbackHandler verifies signature, issuer, audience, expiry, nonce and provider subject before provisioning. Existing local identities cannot be adopted by an OIDC issuer, even if their username matches.
func (*Service) OIDCLoginHandler ¶
func (s *Service) OIDCLoginHandler(w http.ResponseWriter, r *http.Request)
OIDCLoginHandler sends state, nonce and S256 PKCE to the verified issuer. The signed ten-minute state cookie uses Lax only for the top-level SSO callback; local access/refresh/CSRF cookies remain SameSite Strict.
func (*Service) RecoverAdmin ¶
RecoverAdmin applies operator-supplied local administrator recovery before the server accepts traffic. An empty password disables recovery; an empty name selects admin. The master key derives a domain-separated fingerprint key, so the persisted receipt cannot be used to guess passwords without that key.
The singleton server must be the only writer. The receipt is written last: after an interrupted application the next startup repeats the recovery, never treating partially recovered credentials, policy or revocations as complete. Errors must abort startup. No recovery secret is logged or recorded in events.
func (*Service) Refresh ¶
func (s *Service) Refresh(ctx context.Context, w http.ResponseWriter, r *http.Request) (*SessionInfo, error)
Refresh consumes a token once, keeping its hash as a durable replay receipt. Family expiry is absolute rather than extended indefinitely by rotation.
func (*Service) ResetPassword ¶
ResetPassword supports offline administrative recovery and forces a change.
func (*Service) Settings ¶
func (s *Service) Settings(ctx context.Context) (*OIDCSettings, error)
Settings reads one persisted snapshot without joining identity mutations. Public version discovery must remain available while a mutation waits to write.
func (*Service) UpdateAccount ¶
UpdateAccount updates display name, roles, disabled and must-change flags.
func (*Service) UpdateSettings ¶
func (s *Service) UpdateSettings(ctx context.Context, cfg OIDCSettings) error
UpdateSettings validates and seals write-only OIDC credentials at rest.