Best Practices for Storing and Validating Passwords in Java (BCrypt, Argon2, PBKDF2)
Password security is critical for any modern application. Java developers often face the question:
Which algorithm should I use? In this post, we explore BCrypt, PBKDF2, and Argon2 with Spring Security integration and examples.
Why You Should Never Store Plain Text Passwords
Storing passwords as plain text is a major security flaw. Even reversible encryption isn’t good enough.
Instead, use a one-way hash function with salting and multiple iterations to make brute-force and rainbow table attacks infeasible.
BCrypt: The Gold Standard in Spring Security
BCrypt is widely used because it includes built-in salting and work factor (cost). It is also supported natively by Spring Security.
BCrypt Example with Spring Security
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class PasswordUtils {
private static final PasswordEncoder encoder = new BCryptPasswordEncoder();
public static String hashPassword(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String hashedPassword) {
return encoder.matches(rawPassword, hashedPassword);
}
}
Opinion: For most web apps, BCrypt is the best default choice.
PBKDF2: More Control, Less Convenience
PBKDF2 (Password-Based Key Derivation Function 2) allows you to control salt length, iterations, and hash algorithm. Spring Security supports it through Pbkdf2PasswordEncoder.
PBKDF2 Example
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
public class PBKDF2Example {
private static final Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder(
"secret", 185000, 256);
public static String encode(String password) {
return encoder.encode(password);
}
public static boolean validate(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
Opinion: Use PBKDF2 when you need FIPS-compliant hashing or greater configuration flexibility. But setup is more complex than BCrypt.
Argon2: Modern, Secure — But Less Supported
Argon2 is the winner of the Password Hashing Competition and is designed to resist both CPU and GPU cracking attempts. Spring Security 5+ supports it via Argon2PasswordEncoder.
Argon2 Example
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
public class Argon2Example {
private static final Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
public static String hash(String password) {
return encoder.encode(password);
}
public static boolean check(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
Opinion: If you’re working on high-security applications and don’t mind depending on native libraries, Argon2 is worth using.
Choosing the Right One
| Algorithm | Pros | Cons |
|---|---|---|
| BCrypt | Simple, battle-tested, built-in Spring support | Limited configuration |
| PBKDF2 | FIPS-compliant, customizable | Slower than Argon2, more complex config |
| Argon2 | Memory-hard, resistant to GPU cracking | Less mature in JVM world |
For general Spring apps, start with BCrypt. If you’re bound by regulation or need more control, consider PBKDF2. For security-critical systems, evaluate Argon2.
Further Reading
Always hash passwords — no excuses in 2025 or beyond.

