diff --git a/core/src/main/java/org/springframework/security/authentication/CachingUserDetailsService.java b/core/src/main/java/org/springframework/security/authentication/CachingUserDetailsService.java
index da6e7de77d..ba8f6d3695 100644
--- a/core/src/main/java/org/springframework/security/authentication/CachingUserDetailsService.java
+++ b/core/src/main/java/org/springframework/security/authentication/CachingUserDetailsService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,51 +26,29 @@ import org.springframework.util.Assert;
* Implementation of {@link UserDetailsService} that utilizes caching through a
* {@link UserCache}
*
- * If a null {@link UserDetails} instance is got from calling
+ * If a null {@link UserDetails} instance is returned from
* {@link UserCache#getUserFromCache(String)} to the {@link UserCache} got from
* {@link #getUserCache()}, the user load is deferred to the {@link UserDetailsService}
- * provided during construction. Otherwise, the instance got from cache is returned.
+ * provided during construction. Otherwise, the instance retrieved from the cache is
+ * returned.
*
* It is initialized with a {@link NullUserCache} by default, so it's strongly recommended
* setting your own {@link UserCache} using {@link #setUserCache(UserCache)}, otherwise,
* the delegate will be called every time.
*
- * Utilize this class by defining {@link org.springframework.context.annotation.Bean} that
- * encapsulates an actual implementation of {@link UserDetailsService} and set an
- * {@link UserCache}.
+ * Utilize this class by defining a {@link org.springframework.context.annotation.Bean}
+ * that encapsulates an actual implementation of {@link UserDetailsService} and providing
+ * a {@link UserCache} implementation.
*
- * For example: {@code
+ * For example:
* @Bean
- * public CachingUserDetailsService cachingUserDetailsService(UserDetailsService delegate,
- * UserCache userCache) {
+ * public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
+ * UserDetailsService delegate = ...;
* CachingUserDetailsService service = new CachingUserDetailsService(delegate);
* service.setUserCache(userCache);
* return service;
* }
- * }
- *
- *
- * However, a preferable approach would be to use
- * {@link org.springframework.cache.annotation.Cacheable} in your
- * {@link UserDetailsService#loadUserByUsername(String)} implementation to cache
- * {@link UserDetails} by username
, reducing boilerplate and setup, specially
- * if you are already using cache in your application.
- *
- *
- * For example:
- *
- * {@code
- * @Service
- * public class MyCustomUserDetailsImplementation implements UserDetailsService {
-
- * @Override
- * @Cacheable
- * public UserDetails loadUserByUsername(String username) {
- * //some logic here to get the actual user details
- * return userDetails;
- * }
- * }
- * }
+ *
*
* @author Luke Taylor
* @since 2.0
diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/cached.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/cached.adoc
deleted file mode 100644
index 8d58252b6e..0000000000
--- a/docs/modules/ROOT/pages/servlet/authentication/passwords/cached.adoc
+++ /dev/null
@@ -1,38 +0,0 @@
-[[servlet-authentication-cached]]
-= CachingUserDetailsService
-
-Spring Security's `CachingUserDetailsService` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[UserDetailsService] offering support for caching authentication.
-
-`CachingUserDetailsService` provides caching support for `UserDetails` by delegating the authentication process to the provided `UserDetailsService`. The result is then stored in a `UserCache` to reduce computation in subsequent calls.
-
-Utilize this class by defining a `@Bean` of it that encapsulates a concrete implementation of `UserDetailsService` and set a `UserCache` to cache authenticated `UserDetails`.
-
-For example:
-
-[source,java]
-----
-@Bean
-public CachingUserDetailsService cachingUserDetailsService(UserDetailsService delegate, UserCache userCache) {
- CachingUserDetailsService service = new CachingUserDetailsService(delegate);
- service.setUserCache(userCache);
- return service;
-}
-----
-
-However, a preferable approach would be to use `@Cacheable` in your `UserDetailsService.loadUserByUsername(String)` implementation to cache `UserDetails` by `username`, reducing boilerplate and setup, especially if you are already using cache in your application.
-
-For example:
-
-[source,java]
-----
-@Service
-public class MyCustomUserDetailsImplementation implements UserDetailsService {
-
- @Override
- @Cacheable
- public UserDetails loadUserByUsername(String username) {
- // some logic here to get the actual user details
- return userDetails;
- }
-}
-----
diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/caching.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/caching.adoc
new file mode 100644
index 0000000000..9c0d37771e
--- /dev/null
+++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/caching.adoc
@@ -0,0 +1,156 @@
+[[servlet-authentication-caching-user-details]]
+= Caching `UserDetails`
+
+Spring Security provides support for caching `UserDetails` with <>.
+Alternatively, you can use Spring Framework's <> annotation.
+In either case, you will need to <> in order to validate passwords retrieved from the cache.
+
+[[servlet-authentication-caching-user-details-service]]
+== `CachingUserDetailsService`
+
+Spring Security's `CachingUserDetailsService` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[UserDetailsService] to provide support for caching `UserDetails`.
+`CachingUserDetailsService` provides caching support for `UserDetails` by delegating to the provided `UserDetailsService`.
+The result is then stored in a `UserCache` to reduce computation in subsequent calls.
+
+The following example simply defines a `@Bean` that encapsulates a concrete implementation of `UserDetailsService` and a `UserCache` for caching the `UserDetails`:
+
+.Provide a `CachingUserDetailsService` `@Bean`
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Bean
+public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
+ UserDetailsService delegate = ...;
+ CachingUserDetailsService service = new CachingUserDetailsService(delegate);
+ service.setUserCache(userCache);
+ return service;
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Bean
+fun cachingUserDetailsService(userCache: UserCache): CachingUserDetailsService {
+ val delegate: UserDetailsService = ...
+ val service = CachingUserDetailsService(delegate)
+ service.userCache = userCache
+ return service
+}
+----
+======
+
+[[servlet-authentication-caching-user-details-cacheable]]
+== `@Cacheable`
+
+An alternative approach would be to use Spring Framework's {spring-framework-reference-url}integration.html#cache-annotations-cacheable[`@Cacheable`] in your `UserDetailsService` implementation to cache `UserDetails` by `username`.
+The benefit to this approach is simpler configuration, especially if you are already using caching elsewhere in your application.
+
+The following example assumes caching is already configured, and annotates the `loadUserByUsername` with `@Cacheable`:
+
+.`UserDetailsService` annotated with `@Cacheable`
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Service
+public class MyCustomUserDetailsImplementation implements UserDetailsService {
+
+ @Override
+ @Cacheable
+ public UserDetails loadUserByUsername(String username) {
+ // some logic here to get the actual user details
+ return userDetails;
+ }
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Service
+class MyCustomUserDetailsImplementation : UserDetailsService {
+
+ @Cacheable
+ override fun loadUserByUsername(username: String): UserDetails {
+ // some logic here to get the actual user details
+ return userDetails
+ }
+}
+----
+======
+
+[[servlet-authentication-caching-user-details-credential-erasure]]
+== Disable Credential Erasure
+
+Whether you use <> or <>, you will need to disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] so that the `UserDetails` will contain a `password` to be validated when retrieved from the cache.
+The following example disables credential erasure for the global `AuthenticationManager` by configuring the `AuthenticationManagerBuilder` provided by Spring Security:
+
+.Disable credential erasure for the global `AuthenticationManager`
+[tabs]
+=====
+Java::
++
+[source,java,role="primary"]
+----
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ // ...
+ return http.build();
+ }
+
+ @Bean
+ public UserDetailsService userDetailsService() {
+ // Return a UserDetailsService that caches users
+ // ...
+ }
+
+ @Autowired
+ public void configure(AuthenticationManagerBuilder builder) {
+ builder.eraseCredentials(false);
+ }
+
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+import org.springframework.security.config.annotation.web.invoke
+
+@Configuration
+@EnableWebSecurity
+class SecurityConfig {
+
+ @Bean
+ fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
+ // ...
+ return http.build()
+ }
+
+ @Bean
+ fun userDetailsService(): UserDetailsService {
+ // Return a UserDetailsService that caches users
+ // ...
+ }
+
+ @Autowired
+ fun configure(builder: AuthenticationManagerBuilder) {
+ builder.eraseCredentials(false)
+ }
+
+}
+----
+=====
diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/user-details-service.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/user-details-service.adoc
index d3b3ab914f..af6ed15daa 100644
--- a/docs/modules/ROOT/pages/servlet/authentication/passwords/user-details-service.adoc
+++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/user-details-service.adoc
@@ -2,7 +2,7 @@
= UserDetailsService
{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by xref:servlet/authentication/passwords/dao-authentication-provider.adoc#servlet-authentication-daoauthenticationprovider[`DaoAuthenticationProvider`] for retrieving a username, a password, and other attributes for authenticating with a username and password.
-Spring Security provides xref:servlet/authentication/passwords/in-memory.adoc#servlet-authentication-inmemory[in-memory], xref:servlet/authentication/passwords/jdbc.adoc#servlet-authentication-jdbc[JDBC], and xref:servlet/authentication/passwords/cached.adoc#servlet-authentication-cached[in-cache] implementations of `UserDetailsService`.
+Spring Security provides xref:servlet/authentication/passwords/in-memory.adoc#servlet-authentication-inmemory[in-memory], xref:servlet/authentication/passwords/jdbc.adoc#servlet-authentication-jdbc[JDBC], and xref:servlet/authentication/passwords/caching.adoc#servlet-authentication-caching-user-details[caching] implementations of `UserDetailsService`.
You can define custom authentication by exposing a custom `UserDetailsService` as a bean.
For example, the following listing customizes authentication, assuming that `CustomUserDetailsService` implements `UserDetailsService`: