The Ecommerce API uses Spring Security for authentication and authorization. Currently, the API is configured in development mode with authentication disabled to facilitate testing.
Current Security Configuration
The API uses a permissive security configuration suitable for development:
@ Configuration
@ EnableWebSecurity
class SecurityConfig {
@ Bean
public PasswordEncoder passwordEncoder () {
return PasswordEncoderFactories . createDelegatingPasswordEncoder ();
}
@ Bean
public SecurityFilterChain securityFilterChain ( HttpSecurity http ) throws Exception {
http
. csrf (csrf -> csrf . disable ())
. authorizeHttpRequests (auth -> auth . anyRequest (). permitAll ())
. httpBasic (httpBasicAuth -> httpBasicAuth . disable ())
. formLogin (formLoginAuth -> formLoginAuth . disable ());
return http . build ();
}
}
Security Features
CSRF protection is currently disabled for API development. Enable in production for web applications.
All requests are permitted without authentication. This should be restricted in production.
HTTP Basic authentication is disabled.
Form-based login is disabled as this is a REST API.
The current configuration is for development only. All endpoints are publicly accessible. Implement proper authentication before deploying to production.
Password Encoding
Although authentication is not currently enforced, the API properly encodes user passwords using Spring Security’s delegating password encoder.
Password Encoder Configuration
The API uses DelegatingPasswordEncoder, which supports multiple encoding algorithms:
@ Bean
public PasswordEncoder passwordEncoder () {
return PasswordEncoderFactories . createDelegatingPasswordEncoder ();
}
This encoder:
Uses bcrypt as the default algorithm
Supports multiple formats: {bcrypt}, {pbkdf2}, {scrypt}, {sha256}
Allows password migration between algorithms
Stores the algorithm identifier with the encoded password
User Creation with Password Encoding
When creating a user, passwords are automatically encoded:
@ PostMapping ( "/users" )
ResponseEntity < EntityModel < UserView >> save (@ RequestBody User newUser) {
if ( newUser . getPassword () == null || newUser . getPassword (). trim (). isEmpty ()) {
return ResponseEntity . badRequest (). build ();
}
if ( userRepository . existsByEmail ( newUser . getEmail ())) {
return ResponseEntity . badRequest (). build ();
}
String password = passwordEncoder . encode ( newUser . getPassword ());
newUser . setPassword (password);
newUser . setCreatedAt ( LocalDateTime . now ());
User savedUser = userRepository . save (newUser);
return ResponseEntity
. created ( linkTo ( methodOn ( UserController . class ). findOne ( savedUser . getId ())). toUri ())
. body ( assembler . toModel (savedUser));
}
Password Encoding Example
Create User Request
Send a POST request with a plain text password: {
"email" : "[email protected] " ,
"name" : "John Doe" ,
"password" : "mySecurePassword123"
}
Password Encoding
The API encodes the password using bcrypt: String password = passwordEncoder . encode ( newUser . getPassword ());
// Result: {bcrypt}$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Storage
The encoded password is stored in the database. The plain text password is never persisted.
Even though authentication is not enforced, passwords are properly encoded and ready for future authentication implementation.
Future Authentication Implementation
To enable authentication in production, you’ll need to:
Enable Authentication
Modify the security filter chain to require authentication: @ Bean
public SecurityFilterChain securityFilterChain ( HttpSecurity http) throws Exception {
http
. csrf (csrf -> csrf . disable ())
. authorizeHttpRequests (auth -> auth
. requestMatchers ( "/users" , "/products" ). authenticated ()
. anyRequest (). permitAll ()
)
. httpBasic ( Customizer . withDefaults ());
return http . build ();
}
Implement UserDetailsService
Create a service to load user details for authentication: @ Service
public class CustomUserDetailsService implements UserDetailsService {
@ Autowired
private UserRepository userRepository ;
@ Override
public UserDetails loadUserByUsername ( String email )
throws UsernameNotFoundException {
User user = userRepository . findByEmail (email)
. orElseThrow (() -> new UsernameNotFoundException (email));
return org . springframework . security . core . userdetails . User
. withUsername ( user . getEmail ())
. password ( user . getPassword ())
. authorities ( "USER" )
. build ();
}
}
Add JWT or Session Management
Implement JWT tokens or session management for API authentication: // Example: Add JWT filter
http . addFilterBefore (jwtAuthFilter, UsernamePasswordAuthenticationFilter . class );
Enable CSRF for Web Clients
If supporting web browsers, re-enable CSRF protection: . csrf (csrf -> csrf . csrfTokenRepository ( CookieCsrfTokenRepository . withHttpOnlyFalse ()))
Password Validation
The API performs basic password validation:
Password cannot be null or empty
Password is trimmed before encoding
Email uniqueness is enforced
Consider implementing additional password strength requirements for production:
Minimum length (e.g., 8 characters)
Complexity requirements (uppercase, lowercase, numbers, special characters)
Password history to prevent reuse
Security Best Practices
When implementing authentication:
Always use HTTPS in production
Implement rate limiting on authentication endpoints
Add account lockout after failed login attempts
Use secure session management or JWT with short expiration
Enable CSRF protection for web clients
Implement proper role-based access control (RBAC)
Log authentication events for security monitoring
Next Steps
Error Handling Learn how authentication errors are handled
API Reference View the user creation endpoint documentation