{"id":50670538,"url":"https://github.com/cplieger/auth","last_synced_at":"2026-06-08T11:00:33.416Z","repository":{"id":361634234,"uuid":"1255188495","full_name":"cplieger/auth","owner":"cplieger","description":"Composable auth for Go web services: sessions, API keys, passwords, OIDC, WebAuthn/passkeys","archived":false,"fork":false,"pushed_at":"2026-05-31T15:25:03.000Z","size":59,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T16:23:34.911Z","etag":null,"topics":["authentication","go","oidc","passkeys","webauthn"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cplieger.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-31T14:16:56.000Z","updated_at":"2026-05-31T15:24:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cplieger/auth","commit_stats":null,"previous_names":["cplieger/auth"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/cplieger/auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cplieger%2Fauth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cplieger%2Fauth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cplieger%2Fauth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cplieger%2Fauth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cplieger","download_url":"https://codeload.github.com/cplieger/auth/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cplieger%2Fauth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34059157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","go","oidc","passkeys","webauthn"],"created_at":"2026-06-08T11:00:15.289Z","updated_at":"2026-06-08T11:00:33.407Z","avatar_url":"https://github.com/cplieger.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# auth\n\n[![CI](https://github.com/cplieger/auth/actions/workflows/ci.yaml/badge.svg)](https://github.com/cplieger/auth/actions/workflows/ci.yaml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/cplieger/auth.svg)](https://pkg.go.dev/github.com/cplieger/auth)\n[![Go Report Card](https://goreportcard.com/badge/github.com/cplieger/auth)](https://goreportcard.com/report/github.com/cplieger/auth)\n[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](LICENSE)\n\n\u003e Go authentication library: Argon2id passwords, WebAuthn/passkeys, OIDC, sessions, API keys, and RBAC.\n\nA standalone Go authentication library providing password hashing (Argon2id with OWASP parameters), WebAuthn/FIDO2 passkey ceremonies, OIDC provider integration with PKCE, session management with idle/absolute timeouts, API key generation and verification, CSRF token helpers, password-reset/email-verification token primitives, and role-based access control helpers.\n\nDependencies: `golang.org/x/crypto`, `github.com/go-webauthn/webauthn`, `github.com/coreos/go-oidc/v3`, `golang.org/x/oauth2`.\n\n**Note:** HTTP handlers are app-specific and intentionally not included. Consumers should implement their own HTTP layer using the exported authentication primitives.\n\n## Install\n\n```sh\ngo get github.com/cplieger/auth@latest\n```\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/cplieger/auth\"\n)\n\nfunc main() {\n\t// Hash a password (package-level with OWASP defaults)\n\thash, _ := auth.HashPassword(\"my-secure-password\")\n\n\t// Verify\n\tok, _ := auth.VerifyPassword(\"my-secure-password\", hash)\n\t_ = ok\n\n\t// Or use a configurable Hasher with custom params and optional pepper\n\thasher, _ := auth.NewHasher(auth.Argon2Params{\n\t\tMemory: 65536, Iterations: 3, Parallelism: 2,\n\t\tSaltLength: 16, KeyLength: 32,\n\t}, auth.WithPepper([]byte(\"my-secret-pepper\")))\n\thash2, _ := hasher.Hash(\"my-secure-password\")\n\tok2, _ := hasher.Verify(\"my-secure-password\", hash2)\n\t_, _ = hash2, ok2\n\n\t// Set up authenticator with your store implementation (functional options)\n\tauthenticator := auth.NewAuthenticator(\n\t\tmyStore, // implements auth.SessionStore\n\t\tauth.WithIdleTimeout(1*time.Hour),\n\t\tauth.WithAbsTimeout(24*time.Hour),\n\t\tauth.WithLoginPath(\"/login\"),\n\t\tauth.WithCookie(auth.DefaultCookieConfig()),\n\t)\n\n\t// Use in HTTP handler\n\thttp.HandleFunc(\"/api/protected\", func(w http.ResponseWriter, r *http.Request) {\n\t\tuser, _, ok := authenticator.RequireAuth(w, r)\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\t\t_ = user\n\t})\n}\n```\n\n## Configuration\n\nAll configuration is via functional options and function parameters — no import-time side effects, no environment variable reads, no global state initialization.\n\n- `WithLogger(l)`: optional `*slog.Logger`; if nil, uses `slog.Default()`\n- `WithLoginPath(path)`: redirect path for unauthenticated browser requests (default: `\"/login\"`)\n- `WithCookie(cfg)`: configurable cookie name/prefix, Path, SameSite, Domain, Secure (see `CookieConfig`)\n- `WithIdleTimeout(d)`: session idle timeout (default: 1h)\n- `WithAbsTimeout(d)`: session absolute timeout (default: 24h)\n- `WithBypass(fn)`: bypass function for development (synthetic admin user)\n- `NewHasher(params, ...HasherOption)`: configurable Argon2id parameters; use `WithPepper([]byte)` for HMAC peppering\n- `GenerateAPIKey(prefix)`: pass your key prefix (e.g. `\"ak_\"`)\n- `ValidatePasswordContext(password, username, forbiddenWords)`: pass app-specific forbidden words\n\n### Cookie Configuration\n\n```go\ncfg := auth.CookieConfig{\n    Name:     \"my_session\",       // base name (default: \"auth_session\")\n    Prefix:   \"__Host-\",          // HTTPS prefix (default: \"__Host-\"; \"\" to disable)\n    Path:     \"/\",                // cookie path (default: \"/\")\n    Domain:   \"\",                 // cookie domain (default: unset)\n    SameSite: http.SameSiteLaxMode, // (default: Lax)\n    Secure:   nil,                // nil=auto (true when HTTPS), or explicit *bool\n}\nauthenticator := auth.NewAuthenticator(myStore, auth.WithCookie(cfg))\n```\n\n## API\n\n### Password Hashing\n\n- `HashPassword(password) (string, error)` — Argon2id hash in PHC string format (OWASP defaults)\n- `VerifyPassword(password, hash) (bool, error)` — verify hash\n- `NeedsRehash(encodedHash) bool` — check if hash uses outdated parameters\n- `DummyHash() string` — pre-computed hash for constant-time login timing equalization\n- `DefaultArgon2Params() Argon2Params` — OWASP-recommended Argon2id parameters\n- `NewHasher(params, ...HasherOption) (*Hasher, error)` — configurable Argon2id hasher\n- `WithPepper(pepper) HasherOption` — enable HMAC peppering on a Hasher\n- `Hasher.Hash(password) (string, error)` — hash with custom params\n- `Hasher.Verify(password, hash) (bool, error)` — verify with custom params\n- `Hasher.NeedsRehash(hash) bool` — check against custom params\n- `ValidatePasswordLength(password, passwordOnly) error` — NIST length check (max 128)\n- `ValidatePasswordContext(password, username, forbiddenWords) error` — contextual check\n- `CheckBreachedPassword(ctx, client, password) (bool, error)` — HIBP k-anonymity\n\n### Sessions \u0026 Tokens\n\n- `GenerateSessionToken() (plaintext, hash, error)` — 256-bit session token\n- `RotateSessionToken(oldPlaintext) (newPlaintext, newHash, oldHash, error)` — rotation helper\n- `ValidateSession(sess, idle, abs, now) error` — session expiry check\n- `SessionHash(token) string` — SHA-256 hash of plaintext token\n- `HexSHA256(s) string` — hex-encoded SHA-256\n- `CSRFToken(key, sessionHash) (string, error)` — generate CSRF token bound to session\n- `VerifyCSRFToken(key, sessionHash, token, maxAge) error` — verify CSRF token\n- `GenerateOpaqueToken() (plaintext, hash, error)` — for password-reset/email-verification\n- `VerifyOpaqueToken(plaintext, storedHash, expiresAt) error` — verify opaque token\n\n### Cookie Management\n\n- `CookieConfig.CookieName(r) string` — resolve cookie name for request\n- `CookieConfig.SetCookie(w, r, token, maxAge)` — set session cookie\n- `CookieConfig.ReadCookie(r) string` — read session token\n- `CookieConfig.ClearCookie(w, r)` — clear session cookie\n- `SessionCookieName(r) / SetSessionCookie / ReadSessionCookie / ClearSessionCookie` — default-config free functions\n\n### API Keys\n\n- `GenerateAPIKey(keyPrefix) (plaintext, hash, displayPrefix, displaySuffix, error)` — API key generation\n- `VerifyAPIKey(ctx, store, key) (*Key, error)` — API key verification (with expiry check)\n- `APIKeyHash(key) string` — SHA-256 hash of API key\n\n### WebAuthn\n\n- `NewWebAuthn(rpID, rpDisplayName, rpOrigins) (*webauthn.WebAuthn, error)` — WebAuthn setup\n- `NewWebAuthnUser(user, creds) (*WebAuthnUser, error)` — adapt User to webauthn.User interface\n- `BeginRegistration / FinishRegistration / BeginLogin / FinishLogin` — WebAuthn ceremonies\n- `BeginConditionalLogin(wa) (*CredentialAssertion, *SessionData, error)` — conditional mediation (autofill UI)\n\n### OIDC\n\n- `NewOIDCProvider(ctx, cfg) (*OIDCProvider, error)` — OIDC provider with PKCE\n- `ValidateOIDCConfig(cfg) error` — validate OIDC configuration\n- `GenerateOIDCState() (string, error)` — random state parameter\n- `GeneratePKCE() (verifier, challenge, error)` — PKCE S256\n\n### Auth Middleware\n\n- `NewAuthenticator(store, ...Option) *Authenticator` — create authenticator with functional options\n- `NewSessionVerifier(store, ...Option) *SessionVerifier` — session-cookie credential verifier\n- `NewAPIKeyVerifier(store, ...Option) *APIKeyVerifier` — API-key credential verifier\n- `Authenticator.Authenticate(r) (*User, string, error)` — resolve request to user\n- `Authenticator.RequireAuth(w, r) (*User, string, bool)` — auth guard\n- `HasRole(user, role) bool` — RBAC check\n- `ValidateRedirectURI(uri) string` — safe relative-path redirect validation\n- `CanDisableAuthMethod(method, hasPassword, passkeyCount, oidcEnabled, oidcLinked) bool` — check method removal safety\n- `IsBrowserRequest(r) bool` — detect browser vs API client\n- `CredentialVerifier` — interface for pluggable credential verifiers\n- `SessionStore` / `WebAuthnStore` — interfaces for consumer to implement\n- `store.AuthStore` — composite interface (subpackage `github.com/cplieger/auth/store`)\n\n## Subpackages\n\n### `auth/ratelimit`\n\nDual sliding-window per-IP + per-account authentication brute-force rate limiter (OWASP ASVS 2.2.1). Standard library only (`context`, `sync`, `time`).\n\n```go\nrl := ratelimit.NewRateLimiter(ctx, ratelimit.DefaultConfig())\ndefer rl.Stop()\nif allowed, retryAfter := rl.Allow(clientIP, username); !allowed {\n    // reject; retry after retryAfter\n}\n// On successful login, clear the failure counters:\nrl.Reset(clientIP, username)\n```\n\n### `auth/authtest`\n\nExported in-memory `SessionStore` implementation for consumer tests.\n\n```go\nstore := authtest.NewMemStore()\nstore.AddUser(\u0026auth.User{Username: \"test\", Role: auth.RoleUser, Enabled: true})\n```\n\n## Unsupported Features (by design)\n\nThe following features are intentionally out of scope. Each has a documented rationale and, where applicable, a recommended alternative.\n\n| Feature | Rationale |\n|---------|-----------|\n| Full OIDC token-refresh orchestration | Library handles authentication, not long-lived API access. Consumer uses `oauth2.TokenSource`. |\n| Multi-provider OIDC registry | Consumer instantiates multiple `OIDCProvider` instances. |\n| WebAuthn MDS verification | Enterprise feature with large surface. Consumer can call `credential.Verify(mdsProvider)` using stored `RawAttestation`. |\n| OIDC back-channel logout | Enterprise SSO feature beyond scope of auth-primitive library. |\n| Hierarchical RBAC / permission sets | Library provides `HasRole` for flat role check. Use casbin/ory-keto for complex RBAC. |\n| Cookie encryption/signing | Opaque-token architecture; cookie value is a random token, not sensitive data. |\n| OIDC userinfo endpoint | ID token claims sufficient for authentication. Consumer can call `provider.UserInfo()`. |\n| WebAuthn attestation conveyance | Default `none` is correct for most RPs per FIDO Alliance guidance. |\n| WebAuthn credential filtering (AAGUID) | Enterprise policy. Consumer can use go-webauthn's filtering directly. |\n| Passkey well-known endpoints | Browser/credential-manager concern, not server-auth-library concern. |\n| CSRF middleware (full HTTP layer) | Library provides `CSRFToken`/`VerifyCSRFToken` primitives; full middleware is HTTP-framework-specific. |\n\n## License\n\nGPL-3.0 — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcplieger%2Fauth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcplieger%2Fauth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcplieger%2Fauth/lists"}