Skip to main content
nestrs-oauth2 ships a small, focused password-hashing layer behind the password feature. Pick a backend (Bcrypt for legacy hash migration, Argon2id for new deployments), call hash / verify from your service layer, or let the #[derive(HashOnNew)] macro construct a row whose password field is hashed for you.

Enable the feature

The password umbrella pulls in both backends plus the nestrs-oauth2-macros proc-macro crate that powers HashOnNew. Enable just one backend if you know you’ll never need the other:
Available sub-features (all off by default):

Hash and verify

verify (and its alias verify_any) returns Result<bool, HashError>:
  • Ok(true) — password matches.
  • Ok(false) — password does not match (hash was valid).
  • Err(UnknownPrefix(_)) — the stored hash isn’t $2... (bcrypt) or $argon2... (argon2). Indicates a corrupt DB row or a hash from an unsupported algorithm.
  • Err(BcryptDisabled) / Err(Argon2Disabled) — the matched backend’s feature wasn’t enabled.

Pick a backend explicitly

hash_with and verify_with take an explicit Backend:
Backend::default() is Argon2id — Argon2 is the modern OWASP recommendation; Bcrypt is retained only for hash migration. Mixing hashes from different algorithms in the same column is fine as long as you use verify / verify_any (which dispatches on the prefix) rather than verify_with with a hard-coded backend.

The PasswordHasher trait

For code that wants to swap algorithms at runtime — e.g. a migration script that rehashes every row from Bcrypt to Argon2id — there’s a trait with a concrete impl per backend:
BcryptHasher uses the bcrypt crate’s DEFAULT_COST (12 as of bcrypt 0.15). Argon2Hasher uses Argon2::default() (Argon2id, m=19456 KiB, t=2, p=1). Both are Copy + Default + Debug so they slot into your DI registry as Arc<dyn PasswordHasher> if you want backend choice at request time.

#[derive(HashOnNew)] — the new_with_hashed constructor

The proc-macro derive generates an inherent new_with_hashed(...) constructor that hashes every field tagged #[hash] via nestrs_oauth2::password::hash before storing it:
The derive:
  • Takes every named field as a constructor parameter, in struct declaration order. Marked fields take String (the plain input); the macro hashes them before storage.
  • Uses the absolute path ::nestrs_oauth2::password::hash(...) for the hash call — no use statement is needed in user code.
  • Preserves generics (impl<T: Clone> HashOnNew for Foo<T> { ... } works as you’d expect).
  • Errors at compile time if you mark a field with #[hash(args)] — backend selection happens at hash time, not derive time.
Multiple marked fields are supported:

Migration story

Most production migrations move from Bcrypt to Argon2id without service downtime. The recommended pattern:
  1. New rows: hash with hash (Argon2id default) → store the new hash alongside any existing columns.
  2. Login: call verify(plain, &stored) — it dispatches on the hash prefix and works against both Bcrypt and Argon2id rows.
  3. On successful login of a legacy Bcrypt row: rehash with hash_with(plain, Backend::Argon2) and update the column.
  4. After the rollout window, drop the Bcrypt password-bcrypt feature and confirm no $2... rows remain in production.
verify returns Err(HashError::UnknownPrefix(_)) for hashes that aren’t Bcrypt or Argon2 — surface that as a 500 to operations so you can clean up bad rows, never as a “wrong password”.

Why these choices

  • Argon2id as default — modern OWASP recommendation, resistant to GPU and side-channel attacks.
  • No bcrypt re-export at the crate rootbcrypt and argon2 are implementation details of the password module. If you need raw access (custom parameters, custom salt format), depend on those crates directly.
  • Prefix auto-detection in verify_any — lets you mix legacy and new hashes in the same column during migration without branching at every call site.
  • Result<bool, _> instead of bool — distinguishes “hash format unknown” (real error) from “password mismatch” (normal auth failure). Use .unwrap_or(false) at the call site if you want the bool shortcut.

See also

  • mintlify-docs/guides/oauth2 — the parent OAuth2 guide (client, resource server, social, guard).
  • nestrs_oauth2::Backend — the backend enum.
  • nestrs_oauth2::PasswordHasher — the trait for swappable backends.
  • nestrs_oauth2::HashError — the error type returned by hash/verify.