Skip to content

Commit 465e13a

Browse files
author
Mark Putsiata
committed
Document Upgrading Password Encoding
Closes spring-projectsgh-17112 Signed-off-by: Mark Putsiata <[email protected]>
1 parent e30dc42 commit 465e13a

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

docs/modules/ROOT/pages/features/authentication/password-storage.adoc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,3 +689,54 @@ class CompromisedPasswordAuthenticationFailureHandler : AuthenticationFailureHan
689689
}
690690
----
691691
======
692+
693+
[[authentication-upgrading-password-encoding]]
694+
== Upgrading Password Encoding
695+
696+
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.
697+
698+
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`.
699+
700+
To enable this behavior, simply define a `UserDetailsPasswordService` bean. You can always provide your own `UserDetailsPasswordService` implementation tailored to your persistent user store.
701+
702+
For example, if you are using a `UserDetailsManager`, you can write:
703+
704+
.Using UserDetailsPasswordService with UserDetailsManager
705+
[tabs]
706+
======
707+
Java::
708+
+
709+
[source,java,role="primary"]
710+
----
711+
@Bean
712+
UserDetailsPasswordService userDetailsPasswordService(UserDetailsManager userDetailsManager) {
713+
return (user, newPassword) -> {
714+
UserDetails updated = User.withUserDetails(user)
715+
.password(newPassword)
716+
.build();
717+
userDetailsManager.updateUser(updated);
718+
return updated;
719+
};
720+
}
721+
----
722+
723+
Kotlin::
724+
+
725+
[source,kotlin,role="secondary"]
726+
----
727+
@Bean
728+
open fun userDetailsPasswordService(userDetailsManager: UserDetailsManager): UserDetailsPasswordService {
729+
return UserDetailsPasswordService { user, newPassword ->
730+
val updated = User.withUserDetails(user)
731+
.password(newPassword)
732+
.build()
733+
userDetailsManager.updateUser(updated)
734+
updated
735+
}
736+
}
737+
----
738+
======
739+
740+
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)`.
741+
742+
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.

0 commit comments

Comments
 (0)