CEChibuzor Ezeamaku

chi-go-auth.

Authentication is the part of a product you cannot get slightly wrong. So I wrote a library for it, and then I wrote the documents that try to break it.

RoleSole author
WhenMay to June 2026, 64 commits
StackGo, Postgres, SQLite, net/http
StatusPre-1.0 · backs a deployed service
22,018lines of Go, with 42 documents alongside
3storage adapters behind one interface: Postgres, SQLite and in-memory
4security documents: a policy, an audit, a deep review and a pentest

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, migrate and doctor command-line tool, and a plain http.Handler so 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.