CodeGym /Courses /Module 5. Spring /Practice: setting up basic security in a web app

Practice: setting up basic security in a web app

Module 5. Spring
Level 17 , Lesson 5
Available

Today we're getting hands-on — we'll build a minimal web app with Spring Security to protect routes and handle user authentication. Get ready to dive in, folks!


From building the app to adding security

Goal and task structure

Before we type a single line of code, imagine we're building not just an app but a digital restaurant. You need to know who's coming in (authentication) and where they can go (authorization). In a real restaurant there's a bouncer and VIP sections; in our app we'll use Spring Security.

Here's the plan:

  1. Create a minimal Spring Boot app — our "restaurant"
  2. Add basic protection with Spring Security — install the "doors and locks"
  3. Set up a visitor check system — who are you and can we trust you?
  4. Define access rules for different zones — who can go where
  5. Test our security through a browser or Postman — run a test "visit"

Ready to build the most secure digital restaurant? Let's get started!

Step 1: Create a minimalist Spring Boot app

First, create a new Spring Boot project. Pick the dependencies:

  • Spring Web — so the app can handle HTTP requests.
  • Spring Security — for the actual security setup.

Don't forget to use Gradle or Maven in your project. For example, for Maven your pom.xml would look like this:


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

Now let's add a simple controller.


@RestController
public class GreetingController {

    @GetMapping("/public")
    public String publicEndpoint() {
        return "This endpoint is open to everyone!";
    }

    @GetMapping("/secure")
    public String secureEndpoint() {
        return "You've entered the protected area!";
    }
}

Run the app and try opening the /public and /secure routes. Note that Spring Security already protects your API by default. Try hitting /secure and you'll see the browser login screen — that's the out-of-the-box protection Spring Security gives you.

Step 2: Configure basic settings

Now let's create a custom security config. We need to make sure that:

  1. /public stays open to everyone.
  2. /secure is protected and only accessible to authenticated users.

Create a configuration class.


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public").permitAll() // Access is open to everyone
                .anyRequest().authenticated()      // All other requests require authentication
                .and()
            .formLogin()                           // Enable the default login form
                .and()
            .httpBasic();                          // Enable HTTP Basic auth
    }
}

Restart the app. Now /public opens fine, while /secure will ask for a username and password via the default login form.

Step 3: Setting up users

By default Spring Security gives you a built-in user named user and a random password printed in the app logs at startup. If you're tired of hunting through logs for the password, let's add our own users in application.properties.


spring.security.user.name=admin
spring.security.user.password=admin123

Now the admin user can authenticate with password admin123.

But what if we need different roles (for example, admins and regular users)? Let's tweak the setup a bit.

Step 4: Add role-based authorization

We'll add two roles: ROLE_ADMIN and ROLE_USER. First, update our security configuration:


@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/public").permitAll()
            .antMatchers("/secure").hasRole("ADMIN") // Access to /secure only for admins
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .and()
        .httpBasic();
}

Now create users with different roles. Override the configure method in our SecurityConfig class:


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("admin").password(passwordEncoder().encode("admin123")).roles("ADMIN") // Admin
        .and()
        .withUser("user").password(passwordEncoder().encode("user123")).roles("USER");   // Regular user
}

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

Now we have two users:

  • admin with password admin123 and role ROLE_ADMIN.
  • user with password user123 and role ROLE_USER.

And only the administrator (admin) will be able to access /secure.

Step 5: Testing the security

Run the app and test it:

  1. Open /public — it's open to everyone.
  2. Open /secure — the system will ask for login and password.
    • Enter user / user123 — you'll get access denied.
    • Enter admin / admin123 — you'll get access.

You can also use Postman for testing. For example, send a request to /secure with Basic Auth, providing the username and password.

Step 6: Check the application.properties file

Here's something you can add to application.properties to make debugging easier:


# Logging for debugging
logging.level.org.springframework.security=DEBUG

That way you'll see more info about how Spring Security is handling your requests.


Common mistakes

  • Error: protected routes are available to any user. This usually happens because the rules in authorizeRequests are misconfigured. Check the order of antMatchers — they're processed top to bottom.
  • IllegalArgumentException: There is no PasswordEncoder mapped for ID "null". This happens if you forgot to set up a PasswordEncoder. Don't forget to add a BCryptPasswordEncoder bean to your code to encrypt passwords.

The next step is moving user and role storage into a database, which we'll cover in later lectures. Where would we be without real DB integration, right?

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION