Why build it
The Go services I was building needed what better-auth gives a TypeScript app: sessions, social sign-in, second factors and organizations, done correctly and in one place. I wanted that core in Go without adopting a framework. So I scoped the library to the part that matters most, and I built it to a standard I would be comfortable defending line by line.
What it does
- Passwords hashed with Argon2id at NIST SP 800-63B parameters, with a pepper derived through HKDF, optional breach checking against Have I Been Pwned, and timing parity so an attacker cannot tell which accounts exist.
- Sessions as 256-bit opaque tokens, hashed at rest, with sliding expiry and a cookie-or-bearer dual mode.
- Cookies and CSRF using
__Host-prefixed cookies, an origin allowlist and double-submit tokens. - OAuth 2.0 and OpenID Connect with PKCE required on every flow, following RFC 9700.
- Plugins for TOTP with backup codes, magic links, email one-time codes, JWT with a published JWKS, generic OAuth providers and multi-tenant organizations.
- Operations: per-IP and per-account rate limits, a
genkey,migrateanddoctorcommand-line tool, and a plainhttp.Handlerso it drops into any router.
Decisions
Opaque sessions first, JWT as a plugin.
A session you can revoke by deleting a row is simpler to reason about than a token you have to wait out. JWTs are there for the services that need them, not by default.
Secure defaults, not secure options.
PKCE is not a flag. The cookie prefix is not a flag. The safe path is the only path unless you go out of your way.
Write the attack before the release.
The repository carries its own security policy, an audit, a deeper second review and a pentest document. Writing the attack is part of writing the code.
Where it stands
The library is pre-1.0 and not yet public. It backs one of my deployed side projects, and that is how it has been exercised under real use. Publishing it is next.