argon2id
A minimal, secure Argon2id password hashing wrapper for Go with built-in salt generation and constant-time verification.
Repository Health
Technical Analysis
argon2id is a small Go package that wraps the standard library ecosystem’s golang.org/x/crypto/argon2 implementation to make secure password hashing straightforward. It deliberately restricts itself to the Argon2id variant — the variant recommended by the Argon2 RFC for general-purpose password storage — and handles salt generation, parameter encoding, and hash parsing so callers don’t have to work with the underlying primitives directly.
The API surface is intentionally small: CreateHash produces a self-describing hash string (embedding the algorithm version and cost parameters alongside a base64-encoded salt and key), while ComparePasswordAndHash and CheckHash verify a password against that hash using a constant-time comparison to avoid timing attacks. Because parameters are stored in the hash itself, applications can tune memory, iteration, and parallelism costs over time without breaking verification of previously issued hashes.
What You Get
- CreateHash function that generates a self-describing Argon2id hash string
- ComparePasswordAndHash for constant-time password verification
- CheckHash which also returns the Params used to create a hash, useful for detecting outdated cost settings
- DefaultParams preset tuned to runtime.NumCPU() for reasonable out-of-the-box parallelism
- DecodeHash for parsing an existing hash string into its component parameters, salt, and key
Common Use Cases
- Hashing user passwords before storing them in a database during signup
- Verifying a login attempt against a stored Argon2id hash
- Detecting and rehashing passwords created with outdated cost parameters as hardware improves
- Migrating an existing authentication system from bcrypt or scrypt to Argon2id
- Building a Go auth library or framework’s password-hashing layer on top of a vetted primitive
Under The Hood
Architecture The package is a single file (argon2id.go) with no internal layering — a flat, functional design built around three exported entry points (CreateHash, ComparePasswordAndHash, CheckHash) plus a lower-level DecodeHash helper, and one unexported helper (generateRandomBytes) for salt generation. Data flows linearly: CreateHash draws a salt from crypto/rand, derives a key via golang.org/x/crypto/argon2.IDKey, then serializes salt, key, and params into a PHC-style string via fmt.Sprintf; verification reverses this by parsing the format back into Params/salt/key through DecodeHash (built on fmt.Fscanf against a strings.Reader) before re-deriving the key and comparing it with crypto/subtle.ConstantTimeCompare. There’s no interface abstraction or dependency injection — the package is a thin, self-contained wrapper directly over the standard argon2 primitive, so the only thing that would break if the core changed is the hash string format itself, since any change to the $argon2id$v=…$m=…,t=…,p=…$salt$key layout would invalidate previously stored hashes.
Tech Stack
Built for Go 1.18+ to take advantage of generics (CreateHash[T interface{ string | []byte }] and friends accept either a string or []byte password without a runtime type switch). The only external dependency is golang.org/x/crypto v0.14.0 (for the argon2.IDKey implementation), pulling in golang.org/x/sys v0.13.0 transitively. There’s no build tooling beyond the standard go toolchain, no framework, and no database — it’s a pure library consumed via go get and imported directly into whatever binary needs password hashing, relying on crypto/rand, crypto/subtle, and encoding/base64 from the standard library.
Code Quality
A single test file (argon2id_test.go) covers CreateHash for both string and []byte password variants via generics, ComparePasswordAndHash, CheckHash, and DecodeHash — including deliberately malformed-hash cases (junk inserted before/after each of the version, memory, iteration, and parallelism fields, and \r\n injected into the base64 salt/key segment) plus variant-mismatch detection via the ErrIncompatibleVariant sentinel. Errors are handled explicitly through named sentinel errors (ErrInvalidHash, ErrIncompatibleVariant, ErrIncompatibleVersion) rather than panics or silent failures, and naming throughout is clear and idiomatic Go. CI (.github/workflows/go.yml) runs go test -race . across nine Go versions (1.18 through 1.25), giving real confidence in both correctness and forward compatibility, though there’s no dedicated linter configuration (no golangci-lint) beyond the standard toolchain checks.
API Design The public API is intentionally minimal: three top-level functions (CreateHash, ComparePasswordAndHash, CheckHash) cover the entire hash-and-verify lifecycle, and Go generics let callers pass either a string or []byte password without extra conversion boilerplate — getting started requires one import and one call to CreateHash with the provided DefaultParams. Naming is consistent and self-explanatory, every exported symbol carries a godoc comment explaining both what it does and the security reasoning behind it (DefaultParams documents the RFC recommendation behind its values; Params documents the tradeoff of each field), and the returned hash format is self-describing so callers never need to store parameters separately. The tradeoff for this compactness is that DecodeHash and CheckHash surface fairly generic parsing errors rather than pinpointing which field failed, and there are no runnable godoc examples or an examples/ directory beyond the code snippets in the README.
Used by 2 apps in this directory
Wakapi
Developer Tools · Analytics
Self-hosted WakaTime-compatible coding statistics backend that gives developers full control over their coding activity data.
Weaviate
Databases · Search
Open-source vector database combining semantic search, hybrid queries, RAG, and image search in a single cloud-native system built for production scale.