Skip to content

Document Upgrading Password Encoding #17120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,54 @@ class CompromisedPasswordAuthenticationFailureHandler : AuthenticationFailureHan
}
----
======

[[authentication-upgrading-password-encoding]]
== Upgrading Password Encoding

Spring Security can automatically upgrade existing password encodings without asking users to reset their passwords. It uses the `PasswordEncoder.upgradeEncoding(String)` method to determine whether a stored password should be re-encoded for improved security.

If `PasswordEncoder.upgradeEncoding(String)` indicates an update is needed and a `UserDetailsPasswordService` bean is available, the framework will rehash the password immediately after a successful login. The raw password submitted at login is passed to `PasswordEncoder` to produce a stronger encoding. The `UserDetailsPasswordService` saves the newly encoded password in the user store (e.g., database or LDAP) and returns the updated `UserDetails`.

To enable this behavior, simply define a `UserDetailsPasswordService` bean. You can always provide your own `UserDetailsPasswordService` implementation tailored to your persistent user store.

For example, if you are using a `UserDetailsManager`, you can write:

.Using UserDetailsPasswordService with UserDetailsManager
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
UserDetailsPasswordService userDetailsPasswordService(UserDetailsManager userDetailsManager) {
return (user, newPassword) -> {
UserDetails updated = User.withUserDetails(user)
.password(newPassword)
.build();
userDetailsManager.updateUser(updated);
return updated;
};
}
----

Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
open fun userDetailsPasswordService(userDetailsManager: UserDetailsManager): UserDetailsPasswordService {
return UserDetailsPasswordService { user, newPassword ->
val updated = User.withUserDetails(user)
.password(newPassword)
.build()
userDetailsManager.updateUser(updated)
updated
}
}
----
======

When using xref:servlet/authentication/passwords/jdbc.adoc#servlet-authentication-jdbc-bean[JdbcUserDetailsManager], you do not need to register a separate `UserDetailsPasswordService` bean, since `JdbcUserDetailsManager` already implements that interface. You simply enable the upgrade mechanism by calling `JdbcUserDetailsManager.setEnableUpdatePassword(true)`.

This approach lets you migrate from weaker hashes to stronger algorithms (like <<authentication-password-storage-bcrypt,bcrypt>>) without impacting your users. Passwords are re-encoded only after successful authentication, enabling a gradual, transparent migration for your application.