Keywords: Spring Security 5 | Password Encoding Migration | OAuth 2 Configuration
Abstract: This article delves into password encoding issues encountered during migration from Spring Boot 1.4.9 to Spring Boot 2.0 and Spring Security 5. It thoroughly analyzes the root cause of the \"There is no PasswordEncoder mapped for the id \\\"null\\\"\" error and provides solutions based on Spring Security 5's new password storage format, focusing on OAuth 2 client configuration. By comparing different password encoder usage scenarios, the article explains how to correctly apply DelegatingPasswordEncoder and prefix identifiers to ensure backward compatibility during migration. Additionally, it supplements with handling methods for other common configuration problems, helping developers fully understand Spring Security 5's password encoding mechanisms.
Introduction
With the release of Spring Boot 2.0 and Spring Security 5, significant changes in password storage format have led to encoding errors for many developers during migration. Based on a typical migration case, this article analyzes in detail how to resolve the common \"There is no PasswordEncoder mapped for the id \\\"null\\\"\" error and explores the password encoding mechanisms of Spring Security 5.
Problem Background and Error Analysis
When upgrading from Spring Boot 1.4.9 to Spring Boot 2.0 and Spring Security 5, developers often encounter two types of password encoding errors. First, when using BCryptPasswordEncoder, the system may throw an \"Encoded password does not look like BCrypt\" exception, as the old password format does not meet new requirements. Second, more commonly, the \"There is no PasswordEncoder mapped for the id \\\"null\\\"\" error occurs during OAuth 2 authentication, indicating the system cannot identify the password's encoding identifier.
Spring Security 5 introduces a new password storage format, requiring passwords to be stored as {id}encodedPassword, where id identifies the encoding type (e.g., bcrypt). If the password lacks this prefix, the system fails to parse it, causing the above error. In the provided case, the developer correctly configured DelegatingPasswordEncoder, storing passwords in the database as {bcrypt}$2a$10$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ, but the OAuth 2 client configuration did not apply the same format, leading to the issue.
Core Solution
According to the best answer (score 10.0), the key to resolving this problem lies in applying the new password storage format in the OAuth 2 client configuration. Specifically, in ClientDetailsServiceConfigurer, client secrets must include a prefix identifier. For example, modify the original .secret(\"secret\") to .secret(\"{noop}secret\"), where {noop} indicates no-op encoding for plaintext passwords. This ensures client secrets use a consistent format with user passwords, allowing DelegatingPasswordEncoder to correctly identify and process them.
Here is a corrected configuration example:
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(\"test\")
.scopes(\"read\", \"write\")
.authorities(Roles.ADMIN.name(), Roles.USER.name())
.authorizedGrantTypes(\"password\", \"refresh_token\")
.secret(\"{noop}secret\")
.accessTokenValiditySeconds(1800);
}This modification is based on Spring Security 5 documentation, which emphasizes uniformity in password storage format. By adding prefixes, the system can map to the appropriate PasswordEncoder, avoiding the \"null\" identifier error. Additionally, if client secrets are already encrypted, corresponding prefixes (e.g., {bcrypt}) should be used to maintain consistency with user password encoding.
Deep Dive into DelegatingPasswordEncoder
DelegatingPasswordEncoder is a core component of Spring Security 5, supporting multiple encoding formats and dynamically selecting encoders via prefixes. In migration scenarios, it provides backward compatibility, allowing old and new password formats to coexist. Developers can create an instance using PasswordEncoderFactories.createDelegatingPasswordEncoder(), which defaults to supporting encoders like bcrypt and noop.
For handling historical passwords, the documentation recommends using the DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder) method. This can temporarily process old passwords without prefixes, but the long-term solution should be updating all password storage to prefixed formats. In configuration, ensure both UserDetailsService and client configurations use a unified PasswordEncoder to avoid mismatch errors.
Other Configuration Considerations
Beyond client secret configuration, overall security settings must be considered. In SecurityConfiguration, the configureGlobal method should correctly inject UserDetailsService and PasswordEncoder, as shown in the case:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}This ensures user authentication uses the same encoding logic. Simultaneously, OAuth 2 authorization server configuration must integrate the authentication manager via authenticationManagerBean() to coordinate client and user authentication flows.
Supplementary Solutions and Common Pitfalls
Referencing other answers (score 4.0), for in-memory user authentication, formats like .password(\"{noop}password\") can be used, but this is mainly for simple testing scenarios, not production environments. During migration, developers should avoid mixing different encoding formats and regularly check if password storage in the database complies with the new standard.
A common pitfall is applying the new format only to user passwords while neglecting client secrets, which caused the error in the case. Therefore, comprehensively reviewing all password-related configurations is key to successful migration.
Conclusion
When migrating to Spring Security 5, updating password encoding is a critical step. By uniformly applying prefixed password storage formats, especially in OAuth 2 client configurations, the \"There is no PasswordEncoder mapped for the id \\\"null\\\"\" error can be effectively resolved. Developers should deeply understand how DelegatingPasswordEncoder works and ensure consistency across all password handling processes to achieve smooth migration and system security.