Spring Boot: From Basics to Production · Securing APIs with Spring Security

Users, Passwords and Authentication Providers

Load users from the database and hash passwords properly.

For username/password login, implement a UserDetailsService that loads users (with their authorities) from your database, and use a PasswordEncoder — PasswordEncoderFactories.createDelegatingPasswordEncoder() stores an {id} prefix (bcrypt by default) so you can upgrade algorithms later. Spring Security's DaoAuthenticationProvider ties them together, and UserDetailsPasswordService can rehash passwords on login.

@Service
class DbUserDetailsService implements UserDetailsService {
    private final UserRepository users;
    DbUserDetailsService(UserRepository users) { this.users = users; }

    @Override
    public UserDetails loadUserByUsername(String email) {
        var user = users.findByEmailIgnoreCase(email)
                .orElseThrow(() -> new UsernameNotFoundException("Bad credentials"));
        return User.withUsername(user.getEmail())
                .password(user.getPasswordHash())
                .roles(user.getRoles().toArray(String[]::new))
                .disabled(!user.isActive())
                .build();
    }
}

@Bean
PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();   // "{bcrypt}$2a$10$..."
}

Common pitfalls

  • Storing plaintext or reversible passwords.
  • NoOpPasswordEncoder outside of throwaway demos.
  • Revealing whether an email exists through error messages.

Key points

  • UserDetailsService loads users
  • DelegatingPasswordEncoder for upgradeable hashing
  • Generic 'bad credentials' errors

Further reading: Spring Security: Password storage

Practice questions

Why does DelegatingPasswordEncoder prefix hashes with {bcrypt}?

Answer

The prefix identifies the algorithm, so you can switch the default (e.g., to Argon2) while still verifying older hashes and upgrading them on login.

Should UsernameNotFoundException messages reveal the email doesn't exist?

Answer

No; Spring Security converts it to a generic 'Bad credentials' by default to prevent account enumeration.

Open in the app to mark lessons complete, take notes and track your progress.