or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aot-native-support.mdauthentication-core.mdauthentication-events.mdauthentication-management.mdauthentication-tokens.mdauthorities.mdauthorization.mdcompromised-password.mdconcurrent-async.mddao-authentication.mdexpression-access-control.mdindex.mdjaas-authentication.mdjackson-serialization.mdmethod-security.mdobservation-metrics.mdone-time-tokens.mdprovisioning.mdsecurity-context.mdsession-management.mduser-details.md
tile.json

user-details.mddocs/

User Details Services

Interfaces and implementations for loading and managing user information from various data sources. Includes the UserDetails interface, UserDetailsService, in-memory and JDBC implementations, and reactive alternatives.

Key Information for Agents

Core Capabilities:

  • UserDetails interface provides core user information (username, password, authorities, account status)
  • UserDetailsService loads user by username (throws UsernameNotFoundException if not found)
  • UserDetailsManager extends service with CRUD operations (create, update, delete, changePassword)
  • UserDetailsPasswordService updates passwords after authentication (for encoding migration)
  • Reactive support via ReactiveUserDetailsService and ReactiveUserDetailsPasswordService
  • Caching support via UserCache interface and CachingUserDetailsService

Key Interfaces and Classes:

  • UserDetails - Core interface: getUsername(), getPassword(), getAuthorities(), account status methods
  • User - Default implementation with builder pattern (User.withUsername().password().roles().build())
  • UserDetailsService - Interface: loadUserByUsername(String) throws UsernameNotFoundException
  • UserDetailsManager - Extended interface: createUser(), updateUser(), deleteUser(), changePassword(), userExists()
  • InMemoryUserDetailsManager - In-memory implementation (for testing/development)
  • JdbcDaoImpl - JDBC-based UserDetailsService with customizable queries
  • JdbcUserDetailsManager - JDBC-based UserDetailsManager with group management
  • ReactiveUserDetailsService - Returns Mono<UserDetails> (empty Mono if not found)
  • UserCache - Caching interface: getUserFromCache(), putUserInCache(), removeUserFromCache()

Default Behaviors:

  • UserDetails default methods return true for account status checks (non-expired, non-locked, etc.)
  • User.builder() requires username and password (authorities default to empty)
  • roles(String...) automatically prefixes with "ROLE_" (use authorities() for exact strings)
  • JdbcDaoImpl uses default SQL queries (customizable via setter methods)
  • InMemoryUserDetailsManager requires AuthenticationManager for changePassword() validation
  • Reactive service returns empty Mono if user not found (no exception)

Threading Model:

  • Synchronous services execute in calling thread
  • Reactive services return Mono<UserDetails> for non-blocking execution
  • Thread-safe: Implementations should be thread-safe (JDBC implementations are)

Lifecycle:

  • JdbcDaoImpl implements InitializingBean (validates configuration)
  • InMemoryUserDetailsManager stores users in memory (lost on restart)
  • JdbcUserDetailsManager persists to database

Exceptions:

  • UsernameNotFoundException - Thrown when user not found (by synchronous services)
  • Reactive services return empty Mono instead of throwing

Edge Cases:

  • Null username: getUsername() cannot return null (required by interface)
  • Null password: getPassword() may return null (for non-password authentication)
  • Empty authorities: getAuthorities() cannot return null (return empty collection)
  • Account status: All default to true (override in User.builder() if needed)
  • Password encoding: Use passwordEncoder() in builder or encode before setting
  • Custom queries: JdbcDaoImpl allows custom SQL via setter methods
  • Group management: JdbcUserDetailsManager implements GroupManager interface
  • Caching: Use CachingUserDetailsService wrapper or set UserCache on JdbcDaoImpl

Core Interfaces

UserDetails

Provides core user information used by Spring Security.

package org.springframework.security.core.userdetails;

interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();
    String getPassword();
    String getUsername();
    default boolean isAccountNonExpired() { return true; }
    default boolean isAccountNonLocked() { return true; }
    default boolean isCredentialsNonExpired() { return true; }
    default boolean isEnabled() { return true; }
}

Method Details:

  • getAuthorities() - Returns the authorities granted to the user. Cannot return null.
  • getPassword() - Returns the password used to authenticate. May be null or empty if not using password authentication.
  • getUsername() - Returns the username used to authenticate. Cannot return null.
  • isAccountNonExpired() - Returns true if the account is not expired (default: true).
  • isAccountNonLocked() - Returns true if the account is not locked (default: true).
  • isCredentialsNonExpired() - Returns true if the credentials have not expired (default: true).
  • isEnabled() - Returns true if the account is enabled (default: true).

UserDetailsService

Loads user-specific data during authentication.

package org.springframework.security.core.userdetails;

interface UserDetailsService {
    UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException;
}

Method Details:

  • loadUserByUsername(String) - Locates the user based on username. Throws UsernameNotFoundException if user not found.

Usage Example:

public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException(
                "User not found: " + username));

        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .authorities(user.getRoles())
            .accountExpired(!user.isActive())
            .accountLocked(user.isLocked())
            .disabled(!user.isEnabled())
            .build();
    }
}

ReactiveUserDetailsService

Reactive version for non-blocking user loading.

package org.springframework.security.core.userdetails;

interface ReactiveUserDetailsService {
    Mono<UserDetails> findByUsername(String username);
}

Method Details:

  • findByUsername(String) - Reactively locates user. Returns empty Mono if user not found.

Usage Example:

public class CustomReactiveUserDetailsService
        implements ReactiveUserDetailsService {

    private final ReactiveUserRepository userRepository;

    @Override
    public Mono<UserDetails> findByUsername(String username) {
        return userRepository.findByUsername(username)
            .map(user -> User.withUsername(user.getUsername())
                .password(user.getPassword())
                .authorities(user.getRoles())
                .build());
    }
}

UserDetailsPasswordService

Updates user password after successful authentication.

package org.springframework.security.core.userdetails;

interface UserDetailsPasswordService {
    UserDetails updatePassword(UserDetails user, String newPassword);
}

Method Details:

  • updatePassword(UserDetails, String) - Updates the specified user with a new password. Returns updated UserDetails.

Usage Example:

public class CustomUserDetailsPasswordService
        implements UserDetailsPasswordService {

    private final UserRepository userRepository;

    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        // Update in database
        userRepository.updatePassword(user.getUsername(), newPassword);

        // Return updated user details
        return User.withUserDetails(user)
            .password(newPassword)
            .build();
    }
}

// Used with DaoAuthenticationProvider for password encoding migration
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setUserDetailsPasswordService(passwordService);
provider.setPasswordEncoder(newPasswordEncoder);

ReactiveUserDetailsPasswordService

Reactive version for password updates.

package org.springframework.security.core.userdetails;

interface ReactiveUserDetailsPasswordService {
    Mono<UserDetails> updatePassword(UserDetails user, String newPassword);
}

Method Details:

  • updatePassword(UserDetails, String) - Reactively updates password.

AuthenticationUserDetailsService

Loads UserDetails from an Authentication token rather than username.

package org.springframework.security.core.userdetails;

interface AuthenticationUserDetailsService<T extends Authentication> {
    UserDetails loadUserDetails(T token) throws UsernameNotFoundException;
}

Method Details:

  • loadUserDetails(T) - Loads user details from an authentication token (e.g., for pre-authenticated scenarios).

UserDetailsChecker

Checks user account status.

package org.springframework.security.core.userdetails;

interface UserDetailsChecker {
    void check(UserDetails toCheck);
}

Method Details:

  • check(UserDetails) - Examines user and throws AccountStatusException if invalid.

User Class

User

Default implementation of UserDetails.

package org.springframework.security.core.userdetails;

class User implements UserDetails, CredentialsContainer {
    User(String username, String password, Collection<? extends GrantedAuthority> authorities);
    User(String username, String password, boolean enabled, boolean accountNonExpired,
        boolean credentialsNonExpired, boolean accountNonLocked,
        Collection<? extends GrantedAuthority> authorities);

    static UserBuilder withUsername(String username);
    static UserBuilder withUserDetails(UserDetails userDetails);
    @Deprecated
    static UserBuilder withDefaultPasswordEncoder();

    String getUsername();
    String getPassword();
    Collection<GrantedAuthority> getAuthorities();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
    void eraseCredentials();
    boolean equals(Object obj);
    int hashCode();
    String toString();
}

Constructor Details:

  • Simple constructor takes username, password, and authorities.
  • Full constructor includes all account status flags.

Static Factory Methods:

  • withUsername(String) - Returns a builder for constructing users.
  • withUserDetails(UserDetails) - Returns a builder initialized from existing user.
  • withDefaultPasswordEncoder() - Deprecated; returns builder with default password encoder (insecure for production).

User.UserBuilder

Builder for creating User instances.

package org.springframework.security.core.userdetails;

class User.UserBuilder {
    UserBuilder username(String username);
    UserBuilder password(String password);
    UserBuilder passwordEncoder(Function<String, String> encoder);
    UserBuilder authorities(GrantedAuthority... authorities);
    UserBuilder authorities(Collection<? extends GrantedAuthority> authorities);
    UserBuilder authorities(String... authorities);
    UserBuilder roles(String... roles);
    UserBuilder accountExpired(boolean accountExpired);
    UserBuilder accountLocked(boolean accountLocked);
    UserBuilder credentialsExpired(boolean credentialsExpired);
    UserBuilder disabled(boolean disabled);
    UserDetails build();
}

Method Details:

  • username(String) - Sets the username.
  • password(String) - Sets the password.
  • passwordEncoder(Function) - Encodes password before storing (applied at build time).
  • authorities(GrantedAuthority...) - Sets authorities from objects.
  • authorities(String...) - Sets authorities from strings.
  • roles(String...) - Sets roles (automatically prefixed with "ROLE_").
  • accountExpired(boolean) - Sets account expired status.
  • accountLocked(boolean) - Sets account locked status.
  • credentialsExpired(boolean) - Sets credentials expired status.
  • disabled(boolean) - Sets disabled status.
  • build() - Builds the UserDetails instance.

Usage Example:

// Simple user creation
UserDetails user = User.withUsername("john")
    .password("{bcrypt}$2a$10$...")
    .authorities("ROLE_USER", "ROLE_ADMIN")
    .build();

// Full user configuration
UserDetails user = User.withUsername("jane")
    .password("{bcrypt}$2a$10$...")
    .roles("USER", "MANAGER")  // Becomes ROLE_USER, ROLE_MANAGER
    .accountExpired(false)
    .accountLocked(false)
    .credentialsExpired(false)
    .disabled(false)
    .build();

// With password encoding
UserDetails user = User.withUsername("bob")
    .password("plainPassword")
    .passwordEncoder(passwordEncoder::encode)
    .authorities("ROLE_USER")
    .build();

// From existing user
UserDetails modified = User.withUserDetails(existingUser)
    .password("{bcrypt}$2a$10$newPassword")
    .build();

UserDetailsManager

UserDetailsManager

Extended interface with CRUD operations for user management.

package org.springframework.security.provisioning;

interface UserDetailsManager extends UserDetailsService {
    void createUser(UserDetails user);
    void updateUser(UserDetails user);
    void deleteUser(String username);
    void changePassword(String oldPassword, String newPassword);
    boolean userExists(String username);
}

Method Details:

  • createUser(UserDetails) - Creates a new user.
  • updateUser(UserDetails) - Updates an existing user.
  • deleteUser(String) - Deletes user by username.
  • changePassword(String, String) - Changes password for current authenticated user.
  • userExists(String) - Checks if user exists.

In-Memory Implementation

InMemoryUserDetailsManager

In-memory user storage for development and testing.

package org.springframework.security.provisioning;

class InMemoryUserDetailsManager
        implements UserDetailsManager, UserDetailsPasswordService {

    InMemoryUserDetailsManager();
    InMemoryUserDetailsManager(UserDetails... users);
    InMemoryUserDetailsManager(Collection<UserDetails> users);
    InMemoryUserDetailsManager(Properties users);

    UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException;
    void createUser(UserDetails user);
    void updateUser(UserDetails user);
    void deleteUser(String username);
    void changePassword(String oldPassword, String newPassword);
    boolean userExists(String username);
    UserDetails updatePassword(UserDetails user, String newPassword);
    void setAuthenticationManager(AuthenticationManager authenticationManager);
}

Constructor Details:

  • No-arg constructor creates empty manager.
  • Varargs constructor initializes with users.
  • Collection constructor initializes with user collection.
  • Properties constructor loads from properties file.

Method Details:

  • setAuthenticationManager(AuthenticationManager) - Required for changePassword() to validate old password.

Usage Example:

// Create users
UserDetails user1 = User.withUsername("john")
    .password("{bcrypt}$2a$10$...")
    .roles("USER")
    .build();

UserDetails user2 = User.withUsername("admin")
    .password("{bcrypt}$2a$10$...")
    .roles("USER", "ADMIN")
    .build();

// Initialize manager
InMemoryUserDetailsManager userDetailsManager =
    new InMemoryUserDetailsManager(user1, user2);

// CRUD operations
UserDetails newUser = User.withUsername("jane")
    .password("{bcrypt}$2a$10$...")
    .roles("USER")
    .build();
userDetailsManager.createUser(newUser);

boolean exists = userDetailsManager.userExists("jane"); // true

UserDetails loaded = userDetailsManager.loadUserByUsername("jane");

userDetailsManager.deleteUser("jane");

// Change password (requires authentication manager)
userDetailsManager.setAuthenticationManager(authenticationManager);
SecurityContextHolder.getContext().setAuthentication(authentication);
try {
    userDetailsManager.changePassword("oldPass", "newPass");
} catch (BadCredentialsException e) {
    // Old password incorrect
    log.error("Password change failed: invalid current password");
} catch (IllegalArgumentException e) {
    // User not found or other validation error
    log.error("Password change failed: {}", e.getMessage());
}

MapReactiveUserDetailsService

Reactive in-memory user details service.

package org.springframework.security.core.userdetails;

class MapReactiveUserDetailsService
        implements ReactiveUserDetailsService, ReactiveUserDetailsPasswordService {

    MapReactiveUserDetailsService(UserDetails... users);
    MapReactiveUserDetailsService(Collection<UserDetails> users);
    MapReactiveUserDetailsService(Map<String, UserDetails> users);

    Mono<UserDetails> findByUsername(String username);
    Mono<UserDetails> updatePassword(UserDetails user, String newPassword);
}

Constructor Details:

  • Takes varargs, collection, or map of users.

Usage Example:

UserDetails user1 = User.withUsername("john")
    .password("{bcrypt}$2a$10$...")
    .roles("USER")
    .build();

UserDetails user2 = User.withUsername("admin")
    .password("{bcrypt}$2a$10$...")
    .roles("ADMIN")
    .build();

MapReactiveUserDetailsService userDetailsService =
    new MapReactiveUserDetailsService(user1, user2);

// Reactive loading
userDetailsService.findByUsername("john")
    .doOnSuccess(user -> log.info("Loaded user: {}", user.getUsername()))
    .subscribe();

JDBC Implementation

JdbcDaoImpl

JDBC-based UserDetailsService implementation.

package org.springframework.security.core.userdetails.jdbc;

class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService,
        MessageSourceAware, InitializingBean {

    static final String DEF_USERS_BY_USERNAME_QUERY =
        "select username,password,enabled from users where username = ?";
    static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
        "select username,authority from authorities where username = ?";
    static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
        "select g.id, g.group_name, ga.authority from groups g, group_members gm, " +
        "group_authorities ga where gm.username = ? and g.id = ga.group_id " +
        "and g.id = gm.group_id";

    JdbcDaoImpl();

    UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException;

    void setDataSource(DataSource dataSource);
    void setUsersByUsernameQuery(String usersByUsernameQueryString);
    void setAuthoritiesByUsernameQuery(String queryString);
    void setGroupAuthoritiesByUsernameQuery(String queryString);
    void setRolePrefix(String rolePrefix);
    void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey);
    void setEnableAuthorities(boolean enableAuthorities);
    void setEnableGroups(boolean enableGroups);
    void afterPropertiesSet();
}

Default Queries:

  • Users Query: select username,password,enabled from users where username = ?
  • Authorities Query: select username,authority from authorities where username = ?
  • Group Authorities Query: Complex join query for group-based authorities

Method Details:

  • setDataSource(DataSource) - Sets the database datasource.
  • setUsersByUsernameQuery(String) - Customizes user loading query.
  • setAuthoritiesByUsernameQuery(String) - Customizes authority loading query.
  • setGroupAuthoritiesByUsernameQuery(String) - Customizes group authority query.
  • setRolePrefix(String) - Sets prefix for roles (default: "ROLE_").
  • setEnableAuthorities(boolean) - Enables/disables direct authority loading (default: true).
  • setEnableGroups(boolean) - Enables/disables group authority loading (default: false).

Usage Example:

// Basic configuration
JdbcDaoImpl jdbcDao = new JdbcDaoImpl();
jdbcDao.setDataSource(dataSource);

// Custom queries
jdbcDao.setUsersByUsernameQuery(
    "select email as username, password_hash as password, active as enabled " +
    "from app_users where email = ?");
jdbcDao.setAuthoritiesByUsernameQuery(
    "select email as username, role as authority " +
    "from user_roles where email = ?");

// Enable groups
jdbcDao.setEnableGroups(true);

// Use in authentication
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(jdbcDao);

JdbcUserDetailsManager

JDBC-based UserDetailsManager with full CRUD support and group management.

package org.springframework.security.provisioning;

class JdbcUserDetailsManager extends JdbcDaoImpl
        implements UserDetailsManager, GroupManager {

    static final String DEF_CREATE_USER_SQL =
        "insert into users (username, password, enabled) values (?,?,?)";
    static final String DEF_DELETE_USER_SQL =
        "delete from users where username = ?";
    static final String DEF_UPDATE_USER_SQL =
        "update users set password = ?, enabled = ? where username = ?";
    static final String DEF_INSERT_AUTHORITY_SQL =
        "insert into authorities (username, authority) values (?,?)";
    static final String DEF_DELETE_USER_AUTHORITIES_SQL =
        "delete from authorities where username = ?";
    static final String DEF_USER_EXISTS_SQL =
        "select username from users where username = ?";
    static final String DEF_CHANGE_PASSWORD_SQL =
        "update users set password = ? where username = ?";

    JdbcUserDetailsManager();
    JdbcUserDetailsManager(DataSource dataSource);

    void createUser(UserDetails user);
    void updateUser(UserDetails user);
    void deleteUser(String username);
    void changePassword(String oldPassword, String newPassword);
    boolean userExists(String username);

    // Group management
    List<String> findAllGroups();
    List<String> findUsersInGroup(String groupName);
    void createGroup(String groupName, List<GrantedAuthority> authorities);
    void deleteGroup(String groupName);
    void renameGroup(String oldName, String newName);
    void addUserToGroup(String username, String group);
    void removeUserFromGroup(String username, String group);
    List<GrantedAuthority> findGroupAuthorities(String groupName);
    void addGroupAuthority(String groupName, GrantedAuthority authority);
    void removeGroupAuthority(String groupName, GrantedAuthority authority);

    // SQL customization
    void setCreateUserSql(String createUserSql);
    void setDeleteUserSql(String deleteUserSql);
    void setUpdateUserSql(String updateUserSql);
    void setCreateAuthoritySql(String createAuthoritySql);
    void setDeleteUserAuthoritiesSql(String deleteUserAuthoritiesSql);
    void setUserExistsSql(String userExistsSql);
    void setChangePasswordSql(String changePasswordSql);
    // ... many more SQL customization methods for groups
}

Method Details:

  • CRUD operations for users: createUser(), updateUser(), deleteUser(), userExists()
  • Password management: changePassword()
  • Group management: create, delete, rename groups; add/remove users; manage group authorities

Usage Example:

// Initialize manager
JdbcUserDetailsManager userDetailsManager =
    new JdbcUserDetailsManager(dataSource);

// Create user
UserDetails newUser = User.withUsername("john")
    .password("{bcrypt}$2a$10$...")
    .roles("USER")
    .build();
userDetailsManager.createUser(newUser);

// Update user
UserDetails updated = User.withUsername("john")
    .password("{bcrypt}$2a$10$newPassword")
    .roles("USER", "ADMIN")
    .accountLocked(true)
    .build();
userDetailsManager.updateUser(updated);

// Group management
userDetailsManager.createGroup("managers",
    AuthorityUtils.createAuthorityList("ROLE_MANAGER"));
userDetailsManager.addUserToGroup("john", "managers");

List<GrantedAuthority> groupAuthorities =
    userDetailsManager.findGroupAuthorities("managers");

// Delete user
userDetailsManager.deleteUser("john");

// Custom SQL
userDetailsManager.setCreateUserSql(
    "insert into app_users (email, password_hash, active) values (?,?,?)");

User Details Wrapper

UserDetailsByNameServiceWrapper

Wraps UserDetailsService as an AuthenticationUserDetailsService.

package org.springframework.security.core.userdetails;

class UserDetailsByNameServiceWrapper<T extends Authentication>
        implements AuthenticationUserDetailsService<T> {

    UserDetailsByNameServiceWrapper();
    UserDetailsByNameServiceWrapper(UserDetailsService userDetailsService);

    UserDetails loadUserDetails(T authentication)
        throws UsernameNotFoundException;
    void setUserDetailsService(UserDetailsService userDetailsService);
}

Usage Example:

UserDetailsService userDetailsService = new JdbcDaoImpl(dataSource);

UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper =
    new UserDetailsByNameServiceWrapper<>(userDetailsService);

// Use with pre-authenticated authentication provider
PreAuthenticatedAuthenticationToken preAuth =
    new PreAuthenticatedAuthenticationToken(username, null);

UserDetails user = wrapper.loadUserDetails(preAuth);

User Cache

UserCache

Caches UserDetails objects to reduce database lookups.

package org.springframework.security.core.userdetails.cache;

interface UserCache {
    UserDetails getUserFromCache(String username);
    void putUserInCache(UserDetails user);
    void removeUserFromCache(String username);
}

NullUserCache

No-op implementation (caching disabled).

package org.springframework.security.core.userdetails.cache;

class NullUserCache implements UserCache {
    NullUserCache();

    UserDetails getUserFromCache(String username);
    void putUserInCache(UserDetails user);
    void removeUserFromCache(String username);
}

SpringCacheBasedUserCache

Implementation using Spring's Cache abstraction.

package org.springframework.security.core.userdetails.cache;

class SpringCacheBasedUserCache implements UserCache, InitializingBean {
    SpringCacheBasedUserCache(Cache cache);

    UserDetails getUserFromCache(String username);
    void putUserInCache(UserDetails user);
    void removeUserFromCache(String username);
    void afterPropertiesSet();
}

Usage Example:

// Configure Spring cache
CacheManager cacheManager = new ConcurrentMapCacheManager("users");
Cache userCache = cacheManager.getCache("users");

// Create cache wrapper
SpringCacheBasedUserCache springUserCache =
    new SpringCacheBasedUserCache(userCache);

// Use with JdbcDaoImpl
JdbcDaoImpl jdbcDao = new JdbcDaoImpl();
jdbcDao.setDataSource(dataSource);
jdbcDao.setUserCache(springUserCache);

// Or with caching wrapper
CachingUserDetailsService cachingService =
    new CachingUserDetailsService(jdbcDao);
cachingService.setUserCache(springUserCache);

Exceptions

UsernameNotFoundException

Thrown when user cannot be found.

package org.springframework.security.core.userdetails;

class UsernameNotFoundException extends AuthenticationException {
    UsernameNotFoundException(String msg);
    UsernameNotFoundException(String msg, Throwable cause);
}

Usage Example:

@Override
public UserDetails loadUserByUsername(String username)
        throws UsernameNotFoundException {
    return userRepository.findByUsername(username)
        .orElseThrow(() -> new UsernameNotFoundException(
            "User not found with username: " + username));
}