Securing APIs with Spring Security Basics
Add the Spring Security starter to a Spring Boot application, understand its default login behavior, and write a basic SecurityFilterChain configuration.
Introduction
An API with no security is one bad day away from a serious incident. Spring Security is the standard way to add authentication and authorization to a Spring Boot application, and Boot's auto-configuration makes it remarkably easy to get a reasonable baseline of protection with almost no code. In this lesson you will add the security starter, see what happens by default the moment it is on the classpath, and write your own SecurityFilterChain to control access explicitly.
- What changes the instant spring-boot-starter-security is added.
- Spring Boot's default login behavior.
- How to write a basic SecurityFilterChain bean.
- Why passwords must always be encoded, never stored as plain text.
- How CSRF protection interacts with stateless REST APIs.
Adding the Security Starter
Add spring-boot-starter-security to your dependencies. Unlike most starters, this one changes application behavior immediately - simply having it on the classpath locks down every endpoint by default.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>The moment this starter is added, every endpoint that was previously open now requires authentication. Do not add it to a project and walk away without testing - existing API calls will start returning 401 Unauthorized.
Default Login Behavior
With no configuration at all, Spring Boot generates a random password at startup, prints it to the console, and secures every endpoint with HTTP Basic and a form login, using a default username of user.
Click Run to see what this code prints.
curl -u user:8f2c1a9e-4b77-4e5a-9c31-77a0c9a441de http://localhost:8080/api/tasksThis default is only ever meant as a signal that security is active and working - it is never something to rely on beyond initial testing. Real applications define their own users (or delegate to an identity provider) and their own access rules.
A Basic SecurityFilterChain
Modern Spring Security configuration is done by declaring a SecurityFilterChain bean rather than extending a base configuration class. The example below allows public access to authentication endpoints while requiring a valid login for everything else.
@Configuration@EnableWebSecuritypublic class SecurityConfig {
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/actuator/health").permitAll() .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) .csrf(csrf -> csrf.disable());
return http.build(); }
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}Click Run to see what this code prints.
Click Run to see what this code prints.
Password Encoding
Passwords must never be stored in plain text. Spring Security's PasswordEncoder abstraction hashes passwords with a strong, salted algorithm; BCryptPasswordEncoder is the standard default choice.
@Servicepublic class UserRegistrationService {
private final UserRepository userRepository; private final PasswordEncoder passwordEncoder;
public UserRegistrationService(UserRepository userRepository, PasswordEncoder passwordEncoder) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; }
public User register(String username, String rawPassword) { User user = new User(); user.setUsername(username); user.setPassword(passwordEncoder.encode(rawPassword)); return userRepository.save(user); }}Always call passwordEncoder.encode() before persisting a password, and never log the raw value anywhere - not even at DEBUG level during development.
CSRF and Stateless APIs
CSRF (Cross-Site Request Forgery) protection is designed for browser-based, session-authenticated applications where a form submission could be forged by another site. A stateless REST API authenticated with tokens (such as JWT) rather than cookies is not vulnerable to CSRF in the same way, which is why the example above disables it - but that decision should be deliberate, not accidental.
| Application Style | CSRF Protection |
|---|---|
| Server-rendered pages with session cookies | Keep enabled (Spring Security's default) |
| Stateless REST API with token-based auth | Commonly disabled, since there is no session cookie to forge |
Common Mistakes
- Shipping the auto-generated startup password to production instead of defining real users.
- Storing passwords with NoOpPasswordEncoder or plain text instead of BCrypt.
- Disabling CSRF without understanding why it was safe to do so for that specific application.
- Using .anyRequest().permitAll() while debugging and forgetting to revert it before deploying.
- Putting authorization rules in the controller instead of centralizing them in the SecurityFilterChain.
Best Practices
- Define explicit rules for every path group rather than relying on the default lockdown behavior.
- Always encode passwords with BCryptPasswordEncoder or a similarly strong algorithm.
- Keep authentication endpoints (login, register) public and lock down everything else by default.
- Make CSRF decisions deliberately based on whether the API is stateless or session-based.
- Review the SecurityFilterChain configuration whenever new endpoints are added.
Frequently Asked Questions
No. HTTP Basic is a simple starting point. Real-world APIs commonly use token-based authentication such as JWT, or delegate entirely to an external identity provider through OAuth2/OIDC.
Adding spring-boot-starter-security secures every endpoint by default as soon as it is on the classpath. You must explicitly permit any endpoint that should remain public in your SecurityFilterChain.
Yes, BCrypt remains a solid, widely trusted choice for password hashing. Spring Security also supports newer algorithms like Argon2 via DelegatingPasswordEncoder if a project specifically needs them.
Key Takeaways
- Adding spring-boot-starter-security immediately secures every endpoint by default.
- A SecurityFilterChain bean is the modern way to declare authorization rules.
- Passwords must always be hashed with a PasswordEncoder like BCrypt, never stored in plain text.
- CSRF protection matters for session-based apps but is commonly disabled for stateless, token-based APIs.
- Never rely on the auto-generated startup password beyond initial local testing.
Summary
Spring Security gives Boot applications a secure-by-default posture the moment the starter is added, and a SecurityFilterChain bean is where you take explicit control of what is public and what requires authentication. The next lesson builds on this foundation with a real login and authentication flow.