Documentation
¶
Overview ¶
Package egauth is a composable authentication toolkit for Go: a set of independent modules you import à la carte and wire together yourself, in the style of the standard library's database/sql — rather than a framework that owns your HTTP router, your database access, or your conventions. The root package itself is deliberately tiny: it exports only Actor, the explicit authenticated-principal value passed to handlers (never smuggled through context.Context). All behavior lives in the sub-packages below.
Modules ¶
identity Accounts & credentials: register, login (Authenticate), password reset, email
verification, magic-link login, change-password / change-email, phone verification,
an independent recovery channel, account deletion, and OAuth identity linking.
tokens Stateless JWT access tokens + single-use refresh tokens with rotation and theft
detection, plus API keys. Reference implementation in tokens/jwt.
sessions Server-side, revocable sessions with idle-timeout (Touch) and fixation defense
(Rotate).
passwords Hashing / policy / breach-check seams plus references: passwords/argon2,
passwords/policy, passwords/breach/hibp, passwords/breach/offline.
mfa TOTP (RFC 6238) with recovery codes. (SMS is intentionally excluded as a factor.)
otp One-time codes (email/SMS), with enumeration-safe HTTP handlers.
passkey WebAuthn / passkeys, including discoverable (usernameless) login.
oauth OAuth2 / OIDC with PKCE-S256 and id_token/nonce/JWKS; ready-made providers
(Google, GitHub, Microsoft, Apple, Okta, Auth0, ...) live in oauth/providers.
ratelimit Pluggable rate-limiting Limiter + token-bucket reference + middleware.
event Dependency-free security-event Sink seam (audit logging, slog adapter).
health Optional Store Ping/readiness seam.
Composable by design ¶
There is no top-level constructor that bundles everything, and that is intentional: each module has its own Service interface, its own Store contract (with in-memory and pgx backends behind a shared cross-backend conformance suite), and functional-option dependency injection. You compose exactly the stack you need. A typical password-login deployment wires identity (verifies credentials and manages the account lifecycle) with tokens (issues the access/refresh pair) — identity never issues tokens or sessions itself, so you pick the token backend that fits.
idStore := identitymem.NewStore() // or adapters/pgx/identity.NewStore(pool)
idSvc := identity.NewService(idStore, argon2.NewHasher(), policy.NewDefaultPolicy())
tkStore := basic.NewMemoryStore() // tokens/basic: the no-custom-claims path
issuer := basic.NewIssuer(basic.Config{ // thin tokens/jwt facade, zero [struct{}]
Store: tkStore, Issuer: "example-app", SecretKey: secret,
AccessTTL: 15 * time.Minute, RefreshTTL: 720 * time.Hour,
})
user, _ := idSvc.Register(ctx, tenantID, email, password)
pair, _ := issuer.IssueTokenPair(ctx, basic.Claims{Subject: user.ID, TenantID: tenantID})
The complete, runnable login + refresh wiring (including the HTTP handlers) lives in the identity package's example tests — see Example, ExampleNewSingleTenant and ExampleLoginHandler.
Multi-tenancy ¶
Multi-tenancy is explicit and pervasive: every Store and Service operation takes a tenantID string. The empty string is the valid single-tenant default partition, so a single-tenant application simply passes "" — or wraps a Service in that module's SingleTenant facade (e.g. identity.NewSingleTenant) to drop the argument from every call.
Security and stability ¶
egauth is security-literate by default (Argon2id, enumeration-resistant auth paths, refresh rotation with theft detection, alg-pinned JWTs, secure-by-default cookies, pre-auth body caps). The full threat model is in SECURITY.md; the module overview and a copy-pasteable quickstart are in README.md. The API is pre-1.0 and still settling; pin a commit or tag in go.mod for reproducible builds (see the Stability section of README.md).
Audit status: egauth's security review to date is an AI-driven audit only; it has not had an independent third-party human security audit, and that risk is accepted for v1.0 — pin a reviewed commit, commission your own audit, or wait if that trade-off is unacceptable. "AI-audited" is not a synonym for "audited". See AUDIT.md for the full review scope and the cautious-user escape hatch.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Actor ¶
type Actor struct {
// UserID is the user's UUID. Set for User and PAT actors; for Service actors the subject
// is the key's own ID, which is stored in KeyID rather than here.
UserID uuid.UUID
// TenantID is the tenant scope in which this actor operates.
TenantID string
// Kind classifies the actor as User, PAT, or Service. The zero value behaves as User.
Kind PrincipalKind
// KeyID is the API key UUID. Non-zero for PAT and Service actors; empty for User actors.
KeyID uuid.UUID
// Scopes holds the set of permission scopes carried by this actor's token. egauth does not
// interpret or enforce scopes — they are provided verbatim for the application's middleware
// to act on (e.g. via WithRequiredScopes).
Scopes []string
}
Actor represents the authenticated entity making a request. It is explicitly passed as an argument to handlers, never transported via context.Context.
Kind classifies the principal as a human (User or PAT) or a machine (Service). A zero-value Actor has Kind == "" which is treated as User by IsHuman/IsMachine, making it safe for tests that do not need principal classification.
func (Actor) HasAllScopes ¶ added in v0.6.0
HasAllScopes reports whether every requested scope is present in the actor's Scopes list. Vacuous truth: calling with no arguments always returns true. It returns false for a nil or empty Scopes slice when at least one scope is requested.
func (Actor) HasAnyScope ¶ added in v0.6.0
HasAnyScope reports whether at least one of the requested scopes is present in the actor's Scopes list. Calling with no arguments always returns false (no scope can satisfy an empty requirement set). It returns false for a nil or empty Scopes slice.
func (Actor) HasScope ¶ added in v0.6.0
HasScope reports whether scope s is present in the actor's Scopes list. It returns false for a nil or empty Scopes slice.
type PrincipalKind ¶ added in v0.6.0
type PrincipalKind string
PrincipalKind classifies the authenticated entity making a request. It lets egauth tell the application whether a request is a user action or a machine action without requiring the application to inspect token internals.
The zero value is the empty string, which Actor.IsHuman treats as User so that a zero-value Actor (e.g. in tests that do not set Kind) is always safe and human.
const ( // User indicates an interactively authenticated human (session or short-lived JWT). // IsHuman returns true; IsMachine returns false. User PrincipalKind = "user" // PAT indicates a Personal Access Token that acts on behalf of a human. // The token carries explicit Scopes; the underlying subject is still the owning user. // IsHuman returns true; IsMachine returns false. PAT PrincipalKind = "pat" // Service indicates a machine/service identity decoupled from any human. // The token's subject is the key's own ID (not a user). IsMachine returns true. Service PrincipalKind = "service" )
Directories
¶
| Path | Synopsis |
|---|---|
|
adapters
|
|
|
otel
module
|
|
|
pgx
module
|
|
|
Package event defines egauth's optional security-event seam.
|
Package event defines egauth's optional security-event seam. |
|
examples
|
|
|
fullstack
command
Package main is a runnable reference application that wires the full egauth stack: identity + tokens with custom claims + MFA (TOTP) + passkey + admin operations + audit events — all over HTTP using only in-memory backends and the standard library mux.
|
Package main is a runnable reference application that wires the full egauth stack: identity + tokens with custom claims + MFA (TOTP) + passkey + admin operations + audit events — all over HTTP using only in-memory backends and the standard library mux. |
|
Package health defines the optional health-check seam implemented by egauth's pgx-backed stores, so readiness/liveness probes can be written against any store without depending on a specific backend or holding a separate handle to the underlying connection pool.
|
Package health defines the optional health-check seam implemented by egauth's pgx-backed stores, so readiness/liveness probes can be written against any store without depending on a specific backend or holding a separate handle to the underlying connection pool. |
|
Package identity is egauth's account and credential-verification module: registration, password login (Authenticate), password reset, email verification, magic-link login, authenticated change-password / change-email, account deletion, and just-in-time provisioning of external (OAuth) identities.
|
Package identity is egauth's account and credential-verification module: registration, password login (Authenticate), password reset, email verification, magic-link login, authenticated change-password / change-email, account deletion, and just-in-time provisioning of external (OAuth) identities. |
|
internal
|
|
|
doctest
command
Command doctest guards the project's prose against API drift.
|
Command doctest guards the project's prose against API drift. |
|
httputil
Package httputil provides shared HTTP helpers used across egauth handler packages.
|
Package httputil provides shared HTTP helpers used across egauth handler packages. |
|
Package janitor provides a lightweight, optional ticker-based eviction helper for egauth's in-memory stores and rate-limit buckets.
|
Package janitor provides a lightweight, optional ticker-based eviction helper for egauth's in-memory stores and rate-limit buckets. |
|
Package keystore provides per-tenant cryptographic isolation for egauth.
|
Package keystore provides per-tenant cryptographic isolation for egauth. |
|
keystoretest
Package keystoretest is the conformance suite every keystore.Store backend must pass.
|
Package keystoretest is the conformance suite every keystore.Store backend must pass. |
|
memory
Package memory is the zero-dependency, in-process keystore.Store backend.
|
Package memory is the zero-dependency, in-process keystore.Store backend. |
|
Package mfa implements multi-factor authentication: time-based one-time passwords (TOTP, RFC 6238 / RFC 4226) for authenticator apps, and single-use recovery codes.
|
Package mfa implements multi-factor authentication: time-based one-time passwords (TOTP, RFC 6238 / RFC 4226) for authenticator apps, and single-use recovery codes. |
|
memory
Package memory provides an in-memory mfa.Store, primarily for tests and single-process use.
|
Package memory provides an in-memory mfa.Store, primarily for tests and single-process use. |
|
storetest
Package storetest provides a shared contract test suite for mfa.Store implementations.
|
Package storetest provides a shared contract test suite for mfa.Store implementations. |
|
Package oauth implements the OAuth2 authorization-code flow (with PKCE) as stateless, composable HTTP handlers.
|
Package oauth implements the OAuth2 authorization-code flow (with PKCE) as stateless, composable HTTP handlers. |
|
providers
Package providers ships ready-made oauth.Provider constructors for well-known identity providers (Discord, GitHub, Google).
|
Package providers ships ready-made oauth.Provider constructors for well-known identity providers (Discord, GitHub, Google). |
|
Package otp implements short numeric one-time passcodes (e.g.
|
Package otp implements short numeric one-time passcodes (e.g. |
|
memory
Package memory provides an in-memory otp.Store, primarily for tests and single-process use.
|
Package memory provides an in-memory otp.Store, primarily for tests and single-process use. |
|
storetest
Package storetest provides a shared conformance suite for otp.Store implementations.
|
Package storetest provides a shared conformance suite for otp.Store implementations. |
|
Package passkey implements WebAuthn / FIDO2 passkeys (registration and login ceremonies) on top of the go-webauthn library, following egauth's conventions: a credential Store (memory + pgx implementations with a shared contract), a Service that runs the ceremonies, and à-la-carte HTTP handlers.
|
Package passkey implements WebAuthn / FIDO2 passkeys (registration and login ceremonies) on top of the go-webauthn library, following egauth's conventions: a credential Store (memory + pgx implementations with a shared contract), a Service that runs the ceremonies, and à-la-carte HTTP handlers. |
|
memory
Package memory provides an in-memory passkey.Store, primarily for tests and single-process deployments.
|
Package memory provides an in-memory passkey.Store, primarily for tests and single-process deployments. |
|
passkeytest
Package passkeytest provides a software WebAuthn authenticator for integration testing passkey flows without network calls or a real hardware authenticator.
|
Package passkeytest provides a software WebAuthn authenticator for integration testing passkey flows without network calls or a real hardware authenticator. |
|
storetest
Package storetest provides a shared conformance suite for passkey.Store implementations.
|
Package storetest provides a shared conformance suite for passkey.Store implementations. |
|
Package passwords defines egauth's password seams — Hasher (hash and constant-time compare), Policy (validate a candidate password), and BreachChecker (k-anonymity breach lookup) — plus the shared error sentinels and the MaxPasswordLength pre-hash DoS cap.
|
Package passwords defines egauth's password seams — Hasher (hash and constant-time compare), Policy (validate a candidate password), and BreachChecker (k-anonymity breach lookup) — plus the shared error sentinels and the MaxPasswordLength pre-hash DoS cap. |
|
breach/hibp
Package hibp implements passwords.BreachChecker against the Have I Been Pwned "Pwned Passwords" range API using k-anonymity: the password is hashed with SHA-1, and only the first five hex characters of that digest are ever sent to the service.
|
Package hibp implements passwords.BreachChecker against the Have I Been Pwned "Pwned Passwords" range API using k-anonymity: the password is hashed with SHA-1, and only the first five hex characters of that digest are ever sent to the service. |
|
breach/offline
Package offline implements passwords.BreachChecker against an in-memory set of known- compromised password SHA-1 hashes loaded once at startup (for example from the downloadable HIBP "Pwned Passwords" offline corpus, or a custom blocklist).
|
Package offline implements passwords.BreachChecker against an in-memory set of known- compromised password SHA-1 hashes loaded once at startup (for example from the downloadable HIBP "Pwned Passwords" offline corpus, or a custom blocklist). |
|
Package ratelimit provides a small, pluggable request-throttling seam for the egauth HTTP handlers and a dependency-free in-memory token-bucket reference implementation.
|
Package ratelimit provides a small, pluggable request-throttling seam for the egauth HTTP handlers and a dependency-free in-memory token-bucket reference implementation. |
|
Package sessions is egauth's server-side session module: opaque session tokens backed by a store, with sliding idle-timeout (Touch), rotation against session fixation (Rotate), and revocation.
|
Package sessions is egauth's server-side session module: opaque session tokens backed by a store, with sliding idle-timeout (Touch), rotation against session fixation (Rotate), and revocation. |
|
Package tokens is egauth's stateless-token module: JWT access tokens plus single-use refresh tokens with rotation, family-based reuse/theft detection, and long-lived API keys.
|
Package tokens is egauth's stateless-token module: JWT access tokens plus single-use refresh tokens with rotation, family-based reuse/theft detection, and long-lived API keys. |
|
basic
Package basic is a non-generic convenience layer over the generic tokens API for the common case of an application that needs NO custom JWT claims.
|
Package basic is a non-generic convenience layer over the generic tokens API for the common case of an application that needs NO custom JWT claims. |
|
jwt
CachingKeyStore wraps a KeyStore with a bounded-TTL, per-tenant in-memory cache so a single request (and the many that follow it within the TTL) does not re-hit the backing key store — typically a database — for every sign and verify.
|
CachingKeyStore wraps a KeyStore with a bounded-TTL, per-tenant in-memory cache so a single request (and the many that follow it within the TTL) does not re-hit the backing key store — typically a database — for every sign and verify. |
|
Package webapp provides NewWebApp, a batteries-included preset that wires the identity and tokens packages into a single mounted http.Handler for the common password web-app case (no custom token claims), with secure-by-default cookies, CSRF and a non-nil event sink.
|
Package webapp provides NewWebApp, a batteries-included preset that wires the identity and tokens packages into a single mounted http.Handler for the common password web-app case (no custom token claims), with secure-by-default cookies, CSRF and a non-nil event sink. |