Security is an essential non-functional aspect of an application. A secure application usually authenticates the users and may also check for authorization to perform tasks based on the user role.
Authentication and authorization are the main components that decide if a user can access and perform the task on the application.
Spring security framework provides complete support for authentication and authorization functionalities of applications.
In this post, we will learn the basics of Spring security, its main components, and create a simple application that implements these features.
Table of Contents
- Spring Security – Hello World example
- How spring security works?
- Customizing the spring security
- Conclusion
Spring Security – Hello World example
The first program that we usually write while learning any language or framework is “Hello world!”. Let us follow the tradition and create our “Hello World” application. 😛
Create a Spring boot application with the below dependencies.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
The spring-boot-starter-security is the starter Spring boot dependency that provides all the required Spring security libraries.
The spring-boot-starter-web dependency provides the necessary dependencies to build a web application.
Create a simple Rest controller, as shown below. The Rest controller returns the message “Hello World!!”.
@RestController public class HelloController { @GetMapping("/") public String getMessage() { return "Hello World!!"; } }
Run the Spring boot application.
Spring security generates a random UUID string that is the password of the application.

If we access the application, we get the default login page as shown below.
Enter the default username user and the password, the random UUID string printed on the application’s console.

After the successful authentication, our controller displays the “Hello World!!” text, as shown below.

How spring security works?
In the previous section, we saw the traditional “Hello World” example of Spring security. Now, let us learn how the Spring security framework internally works to handle application security.
The below image shows the main components of Spring security.

- Authentication filter: Authentication filter receives the user requests. It also forwards them to the authentication manager for authentication.
- Authentication Manager: Uses the authentication provider to perform the authentication process.
- Authentication Provider: The authentication provider validates if the user exists in the system using the User details service and also validates the password using the password encoder.
- User details service: Implements user management responsibility. It searches for the existing user, which is used in the authentication of the user by the provider.
- Password Encoder: Encodes the password before saving and matches the encoded password against a encode type.
- Security Context: The security context holds the user details after the successful authentication and authorization process.
Spring security is a highly customizable framework. We can customize any part of the framework configuration, such as authentication logic, custom representation of the user details, etc.
Customizing the spring security
Customization of spring security is simple and similar to other spring frameworks.
We define custom configurations or override the default implementation to customize certain parts of the framework according to our application requirements.
Changing the default username and password
We can override the username and password by adding the following properties into the Spring boot application’s application.properties configuration file under the /src/main/resources/ directory.
spring.security.user.name=arun spring.security.user.password=test
Creating a new user
In this section, let us see how to use InMemoryUserDetailsManager implementation to create a new user.
@Configuration public class CustomSecurityConfig { @Bean public UserDetailsService userDetailsService() { var userDetailsService = new InMemoryUserDetailsManager(); var user = User.withUsername("arun").password("12345").authorities("read").build(); userDetailsService.createUser(user); return userDetailsService; } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } }
We have created a new user instance with username arun, password 12345, and also a role called read.
We used InMemoryUserDetailsManager implementation(which implements UserDetailsService interface) instance to create a new user instance.
InMemoryUserDetailsManager implementation is a basic implementation provided by the Spring security and is not practical to use in the production environment.
We also need to define a PasswordEncoder bean if we define a custom User details service.
We have defined a NoOpPasswordEncoder bean, that applies no encoding(Not suitable for Production environment) to the user password.
Overriding the security configuration
To override the security configuration, we can create a custom security configuration class and override the required configure() method of the class WebSecurityConfigurerAdapter.
@Configuration public class CustomSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.formLogin().defaultSuccessUrl("/home", true); http.authorizeRequests().anyRequest().authenticated(); } }
We have set the default success URL of the application to “/home” in the above example.
Also, the above configuration applies application security to all the incoming requests.
If we restart the application, we get redirected to the /home URL path after the successful authentication process, and also the default error screen will be displayed(as there is no handler available for this URL path).

Customizing the authentication logic
To customize authentication logic, we can follow the below steps:
- Create a custom class and also implement the AuthenticationProvider interface.
- Also, implement the authenicate() and supports() method.
- Finally, inject the custom provider into the security configuration class. Then, configure the application to make use of the injected custom provider instance with the help of the configure() method.
Let us start with creating a custom authentication provider class called CustomAuthenticationProvider.
Mark the class with the @Component annotation so that it will make the class injectable to the security configuration class.
@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = String.valueOf(authentication.getCredentials()); if ("arun".equals(username) && "12345".equals(password)) { return new UsernamePasswordAuthenticationToken(username, password, Arrays.asList()); } else { throw new BadCredentialsException("authentication Failed!!"); } } @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } }
We need to override the authenticate() method, which handles all the logic related to the authentication.
If the authentication is successful, we return an implementation of the Authentication object that contains all the authentication details.
Spring security registers these authentication details into Security Context.
In the above example, we have returned the authentication instance of type UsernamePasswordAuthenticationToken, which represents the logged-in user’s authentication object.
Also, the supports() method checks for the supported authentication type.
With the above example, we are checking if the Authentication object has a username and password, and it represents the UsernamePasswordAuthenticationToken authentication implementation class.
Also, if the credentials are not correct, the application throws the BadCredentialsException with a message.

Configure the security configuration class by injecting the authentication provider and also configuring the authentication provider.
@Configuration public class CustomSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider authProvider; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } @Override public void configure(HttpSecurity http) throws Exception { http.formLogin().defaultSuccessUrl("/home", true); http.authorizeRequests().anyRequest().authenticated(); } @Bean public UserDetailsService userDetailsService() { var userDetailsService = new InMemoryUserDetailsManager(); var user = User.withUsername("arun").password("12345").authorities("read").build(); userDetailsService.createUser(user); return userDetailsService; } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } }
With the help of AuthenticationManagerBuilder, we have configured our application to use the custom authentication provider implementation.
Congratulations! We have learned the basics of Spring security and also learned how to customize a few of the security configurations of our Spring boot application.
Conclusion
In this article, we learned the basics of Spring security.
We also learned how internally Spring security handles the authentication.
Finally, we learned how to customize a few of the Spring security configurations.
Example code is available on Github.