Loading users with UserDetailsService

Spring Security · lesson 4 of 31 · 3 min read

Connect your own user table to Spring Security by implementing a single lookup method.

Open this lesson in the learning hub

Key points

  • Spring Security never reads your database. You supply one method: loadUserByUsername.
  • Return a UserDetails: username, the encoded password, authorities, plus enabled and locked flags.
  • User missing? Throw UsernameNotFoundException. Never return null.
  • DaoAuthenticationProvider then compares the submitted password to the stored hash using your PasswordEncoder.
  • Expose a UserDetailsService bean and Boot wires it automatically. InMemoryUserDetailsManager is fine for tests.

Example

@Service
public class JpaUserDetailsService implements UserDetailsService {

    private final UserRepository users;

    public JpaUserDetailsService(UserRepository users) {
        this.users = users;
    }

    @Override
    public UserDetails loadUserByUsername(String email) {
        AppUser u = users.findByEmail(email)
            .orElseThrow(() -> new UsernameNotFoundException("No user " + email));

        return User.withUsername(u.getEmail())
            .password(u.getPasswordHash())          // already BCrypt-encoded
            .authorities(u.getRoles().stream()      // e.g. "ROLE_USER", "post:edit"
                          .map(SimpleGrantedAuthority::new)
                          .toList())
            .accountLocked(u.isLocked())
            .disabled(!u.isActive())
            .build();
    }
}

You own the user lookup; Spring Security only asks for one object back.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Security course, and every lesson in it is listed on the Spring Security contents page.