Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Spring Security & JWT Auth

Spring Security Basics

  • Spring Security Overview
  • JWT Authentication

Authorization

  • Role-Based Access Control
  • Password Encoding
  • OAuth2 & Social Login Basics
Chaturmind
← Spring Security & JWT Auth

Spring Security Basics

  • Spring Security Overview
  • JWT Authentication

Authorization

  • Role-Based Access Control
  • Password Encoding
  • OAuth2 & Social Login Basics
HomeLearnSpring BootSpring SecurityCredentials & Sessions
✓ FreeBeginner· 11 min read

Password Encoding

Use BCryptPasswordEncoder to hash passwords securely and understand why plaintext is never acceptable.

Published March 4, 2025


Password Encoding in Spring Security

Passwords must never be stored in plaintext. Spring Security's PasswordEncoder abstraction makes it easy to hash passwords with modern algorithms.

Why Not Plaintext or MD5/SHA

  • Plaintext: any DB breach immediately exposes all passwords
  • MD5/SHA-1: fast hash functions — attackers can test billions of guesses per second using GPUs
  • BCrypt: intentionally slow, has a built-in salt, work factor is adjustable

BCryptPasswordEncoder

// Register as a bean
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12); // strength/rounds (default 10)
    // Each round increase doubles the work: 12 rounds ≈ 4× slower than 10
}

// Usage in registration
@Service
@RequiredArgsConstructor
public class UserService {
    private final PasswordEncoder encoder;
    private final UserRepository repo;

    public User register(RegisterRequest req) {
        String hash = encoder.encode(req.password());
        // "$2a$12$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
        //  ^   ^  ^
        //  |   |  salt (22 chars) + hash
        //  |   rounds
        //  BCrypt version
        return repo.save(new User(req.email(), hash));
    }

    public boolean checkPassword(String raw, String encoded) {
        return encoder.matches(raw, encoded);
        // Extracts salt from encoded, re-hashes raw, compares
    }
}

DelegatingPasswordEncoder — supporting multiple algorithms

Spring's default encoder since Spring Security 5: allows using different algorithms and migrating over time.

// Default: uses bcrypt, but can verify passwords encoded with other schemes
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

// Stored as: {bcrypt}$2a$10$...
// Or: {sha256}...
// The prefix tells DelegatingPasswordEncoder which algorithm to use for verification

String encoded = encoder.encode("password"); // {bcrypt}$2a$10$...
encoder.matches("password", encoded); // true

Handling Password in Registration Flow

@PostMapping("/api/v1/auth/register")
public ResponseEntity<Void> register(
        @RequestBody @Valid RegisterRequest request) {
    if (userRepository.existsByEmail(request.email())) {
        throw new ConflictException("Email already registered");
    }
    userService.register(request);
    return ResponseEntity.status(201).build();
}

record RegisterRequest(
    @NotBlank @Email String email,
    @NotBlank @Size(min = 8, max = 100) String password,
    @NotBlank String name
) {}

Password Reset Flow

// 1. Generate a secure token
String token = UUID.randomUUID().toString();
resetTokenRepo.save(new PasswordResetToken(userId, token,
    Instant.now().plus(1, ChronoUnit.HOURS)));

// 2. Email the user a link with the token
// https://app.com/reset-password?token=<token>

// 3. On reset form submission
public void resetPassword(String token, String newPassword) {
    PasswordResetToken prt = resetTokenRepo.findByToken(token)
        .filter(t -> t.getExpiry().isAfter(Instant.now()))
        .orElseThrow(() -> new InvalidTokenException("Token invalid or expired"));

    userRepository.findById(prt.getUserId()).ifPresent(user -> {
        user.setPasswordHash(encoder.encode(newPassword));
        userRepository.save(user);
        resetTokenRepo.delete(prt); // single-use
    });
}

Interview Tips

  1. BCrypt cost factor: doubling the cost doubles the time. A cost of 10 takes ~100ms; 12 takes ~400ms. 400ms is fine for login but terrible for bulk imports — use a background migration.
  2. Salt: BCrypt generates a random 22-character salt per password automatically. You do NOT need to manage the salt separately.
  3. Timing attacks: encoder.matches() uses constant-time comparison to prevent timing attacks — never use String.equals() to compare password hashes.

Previous

Role-Based Access Control

Next

OAuth2 & Social Login Basics

AI Tutor

Lesson: Password Encoding

Quick actions

AI responses can be inaccurate. Verify critical information.