spring-projects/spring-security · warning
User.withDefaultPasswordEncoder() is considered unsafe for…
Error message
User.withDefaultPasswordEncoder() is considered unsafe for production and is only intended for sample applications.
What it means
User.withDefaultPasswordEncoder() is a deprecated convenience factory that builds a User with a delegating password encoder. Because a plain-text default password encoding is insecure, calling it logs this warning; it is intended only for demos and samples.
Solutions
- Use User.withUsername(...).password(encoder.encode(rawPassword)) with an explicitly configured PasswordEncoder (e.g. BCryptPasswordEncoder or DelegatingPasswordEncoder)
- Use PasswordEncoderFactories.createDelegatingPasswordEncoder() and store {bcrypt}-prefixed hashes
- Keep withDefaultPasswordEncoder only in non-production sample code
Example fix
// before
User user = User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build();
// after
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
User user = User.withUsername("user")
.password(encoder.encode("password")).roles("USER").build(); Defensive patterns
Strategy: validation
Validate before calling
// Reject the insecure builder in your own code via an ArchUnit/checkstyle rule or review gate
if (stackContains("withDefaultPasswordEncoder")) {
throw new IllegalStateException("User.withDefaultPasswordEncoder() is not allowed in production code");
} Prevention
- Always inject and use a PasswordEncoder for user construction
- Store only encoded, salted hashes ({bcrypt}...) never raw passwords
- Add static analysis or code-review rules banning withDefaultPasswordEncoder outside samples
When it happens
Trigger: Any invocation of User.withDefaultPasswordEncoder(), typically in test/demo code such as User.withDefaultPasswordEncoder().username("user").password("pass").roles("USER").build().
Common situations: Copy-pasted sample configs copied into production; tutorials using the convenience builder; quick local prototypes.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- defaultPasswordEncoderForMatches cannot be null
- encode is not supported
- Encoded password does not look like BCrypt
- id cannot contain
- id cannot contain
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/4e49b1290b2d537d.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/springframework/security/core/userdetails/User.java:283
*
* <pre>
* <code>
* UserDetails user = User.withUsername("user")
* .password("{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG")
* .roles("USER")
* .build();
* </code> </pre>
* @return a UserBuilder that automatically encodes the password with the default
* PasswordEncoder
* @deprecated Using this method is not considered safe for production, but is
* acceptable for demos and getting started. For production purposes, ensure the
* password is encoded externally. See the method Javadoc for additional details.
* There are no plans to remove this support. It is deprecated to indicate that this
* is considered insecure for production purposes.
*/
@Deprecated
public static UserBuilder withDefaultPasswordEncoder() {
logger.warn("User.withDefaultPasswordEncoder() is considered unsafe for production "
+ "and is only intended for sample applications.");
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return builder().passwordEncoder(encoder::encode);
}
public static UserBuilder withUserDetails(UserDetails userDetails) {
// @formatter:off
UserBuilder result = withUsername(userDetails.getUsername())
.accountExpired(!userDetails.isAccountNonExpired())
.accountLocked(!userDetails.isAccountNonLocked())
.authorities(userDetails.getAuthorities())
.credentialsExpired(!userDetails.isCredentialsNonExpired())
.disabled(!userDetails.isEnabled());
// @formatter:on
if (userDetails.getPassword() != null) {
result.password(userDetails.getPassword());
}
return result;View on GitHub (pinned to 96852e8860)