I just announced the newSpring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY


1. Overview

This article discusses a critical part of the registration process – password encoding – basically not storing the password in plaintext.

There are a few encoding mechanism supported by Spring Security – and for the article we’ll use BCrypt, as it’s usually the best solution available.

Most of the other mechanism, such as the MD5PasswordEncoder and ShaPasswordEncoder use weaker algorithms and are now deprecated.

Further reading:

New Password Storage In Spring Security 5

A quick guide to understanding password encryption in Spring Security 5 and migrating to better encryption algorithms.

Read more

Allow Authentication from Accepted Locations Only with Spring Security

Learn how to only allow users to authenticate from accepted locations only with Spring Security.

Read more

Spring Security – Auto Login User After Registration

Learn how to quickly auto-authenticate a user after they complete the registration process.

Read more

2. Define the Password Encoder

We’ll start by defining the simple BCryptPasswordEncoder as a bean in our configuration:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Older implementations – such as SHAPasswordEncoder – would require the client to pass in a salt value when encoding the password.

BCrypt, however, will internally generate a random salt instead. This is important to understand because it means that each call will have a different result, and so we need to only encode the password once.

Also be aware that the BCrypt algorithm generates a String of length 60, so we need to make sure that the password will be stored in a column that can accommodate it. A common mistake is to create a column of a different length and then get an Invalid Username or Password error at authentication time.

3. Encode the Password on Registration

We will now use the PasswordEncoder in our UserService to hash the password during the user registration process:

Example 3.1. – The UserService Hashes the Password

@Autowired
private PasswordEncoder passwordEncoder;

@Override
public User registerNewUserAccount(UserDto accountDto) throws EmailExistsException {
    if (emailExist(accountDto.getEmail())) {
        throw new EmailExistsException(
          "There is an account with that email adress:" + accountDto.getEmail());
    }
    User user = new User();
    user.setFirstName(accountDto.getFirstName());
    user.setLastName(accountDto.getLastName());
    
    user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
    
    user.setEmail(accountDto.getEmail());
    user.setRole(new Role(Integer.valueOf(1), user));
    return repository.save(user);
}

4. Encode the Password on Authentication

Let’s now handle the other half of this process and encode the password when the user authenticates.

First, we need to inject the password encoder bean we defined earlier into our authentication provider:

@Autowired
private UserDetailsService userDetailsService;

@Bean
public DaoAuthenticationProvider authProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(encoder());
    return authProvider;
}

The security configuration is simple:

  • we are injecting our implementation of the users details service
  • we are defining an authentication provider that references our details service
  • we are also enabling the password encoder

And finally, we need to reference this auth provider in our security XML configuration:

<authentication-manager>
    <authentication-provider ref="authProvider" />
</authentication-manager>

Or, in case you’re using Java configuration:

@Configuration
@ComponentScan(basePackages = { "org.baeldung.security" })
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider());
    }
    
    ...
}

5. Conclusion

This quick tutorial continues the Registration series by showing how to properly store the password in the database by leveraging the simple but very powerful BCrypt implementation.

The full implementation of this Registration with Spring Security tutorial can be found in the GitHub project – this is an Eclipse based project, so it should be easy to import and run as it is.

Next »
The Registration API becomes RESTful
« Previous
Spring Security Registration – Resend Verification Email

I just announced the new Spring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

newest oldest most voted
Notify of
jmzc
Guest
jmzc

Thanks for your article. One question: if salt is random when encoding is called , how can BCrypt check if password sumitted by user matches with the store one ?

Eugen Paraschiv
Guest

That’s a great question. BCrypt generates the salt internally, and then stores it concatenated with the cost and the cipher, in a single field, delimited by $. It then uses it on authentication. Hope that helps. Cheers,
Eugen.

bzagh
Guest
bzagh

I still get a Invalid Username or Password error even though the password column is 255 long, and I get a warning on the console from BCrypt saying : “Encoded password does not look like BCrypt”. Any help would be deeply appreciated.

Eugen Paraschiv
Guest

Is that using the project on github? If so – please open up a bug/issue there with a bit more detail and I’ll take a look. Cheers,
Eugen.

אודליה
Guest
אודליה

what if I am using Java for configuration of the security? how can I refer the auth to it not via XML file?

Eugen Paraschiv
Guest

I’ll add a Java section to the article – thanks for the suggestion. Cheers,
Eugen.

Joe
Guest
Joe

Eugene, thanks for doing this. Just a quick note: I was not able to find in the source code the “encoder()” method mentioned in step 4, but if you simply replace it for the “Autowired” “passwordEncoder” object that you’ll have to declare somewhere, it does the trick. Hope that helps someone out there. Again thanks.

Grzegorz Piwowarek
Guest
Grzegorz Piwowarek