The generated user and password
Add spring-boot-starter-security and do nothing else, and Boot auto-configures an
in-memory UserDetailsService with a single user named user and a random UUID
password, then logs that password.
The message is not subtle — it says outright that the configuration must be updated before production.
Using generated security password: %s
This generated password is for development use only. Your security configuration must be updated before running your application in production.Spring Boot auto-configured an in-memory user because no UserDetailsService was defined. Logged at WARN, once, at startup — and it is telling you the configuration is incomplete.
Read in: spring-boot module/spring-boot-security/…/UserDetailsServiceAutoConfiguration.java — getOrDeducePasswordTwo things about it are worth knowing.
It is logged at warn, not info. That is deliberate, and it means it survives
the log level most production deployments run at. Which is good, except that it also
means the password is in your log aggregator, readable by anyone with access to logs
and retained for as long as your retention policy says.
It only appears when the password was generated. The check is
user.isPasswordGenerated(), so the moment you configure any real authentication the
warning stops. Its absence is the signal you want.
// Real applications: define a UserDetailsService (or an OAuth2/OIDC login,// or an LDAP provider) so no user is auto-generated at all.@BeanUserDetailsService users(PasswordEncoder encoder, UserRepository repo) { return username -> repo.findByUsername(username) .map(u -> User.withUsername(u.getUsername()) .password(u.getPasswordHash()) .roles(u.getRoles()) .build()) .orElseThrow(() -> new UsernameNotFoundException(username));}What you should not do is the middle option that looks like a fix:
# Not a fix. A hardcoded credential in a file you are about to commit.spring: security: user: name: admin password: hunter2spring.security.user.* exists for development convenience. Setting it silences the
warning while making the credential permanent and shared, which is worse than the
generated password it replaced.
grep -i "using generated security password" application.logNo match in a production startup log is the correct result. If it matches, the running
application accepts user plus that password.
Replacing auto-configuration with a real UserDetailsService means there is no
fallback account. If your user store is empty or unreachable at startup, nobody can
log in — including you. Seed an initial administrator deliberately, through a
migration or a bootstrap command, rather than relying on the generated user to exist.
If the generated password ever reached a shared log system, treat it as disclosed: rotate whatever it protected rather than assuming nobody read the logs.
Related
Section titled “Related”- SecurityFilterChain — where real authentication is wired
- Django’s equivalent is SECRET_KEY, where the framework also
ships a development value and marks it as one —
django-insecure-in the value itself.