Backend
6/17/2026
4 min read

Mastering Spring Security 7 with Spring Boot 4 - Part 2: Understanding Authentication and Authorization

Mastering Spring Security 7 with Spring Boot 4 - Part 2: Understanding Authentication and Authorization

In the previous article, we learned how to add Spring Security to a Spring Boot application and secure our first REST API.

However, simply protecting endpoints is not enough. Real-world applications require different users to have different levels of access. For example, customers should not be able to perform administrative operations, and administrators should have privileges that normal users do not.

This is where authentication and authorization come into the picture.

In this article, we will understand these two fundamental concepts and implement role-based access control using Spring Security 7 with Spring Boot 4 and Java 21.

What is Authentication?

Authentication is the process of verifying a user's identity.

In simple words, authentication answers the question:

"Who are you?"

Examples:

  • Username and password login

  • OTP verification

  • Fingerprint authentication

  • JWT token validation

  • Google OAuth login

If the identity is valid, the user is authenticated.

What is Authorization?

Authorization determines what resources an authenticated user can access.

Authorization answers the question:

"What are you allowed to do?"

Example:

User Role

Access

USER

View Products

ADMIN

Add Products

ADMIN

Delete Products

USER

Place Orders

A user may be authenticated successfully but still be denied access to certain APIs.

Authentication vs Authorization

Authentication

Authorization

Identifies user

Determines permissions

Happens first

Happens after authentication

Answers "Who are you?"

Answers "What can you do?"

Username and password

Roles and privileges

Creates Security Context

Checks permissions

Real-World Example

Consider an E-Commerce Application.

Customer

Allowed to:

  • View products

  • Place orders

  • Track orders

Not allowed to:

  • Add products

  • Delete products

Admin

Allowed to:

  • Manage products

  • Manage inventory

  • View reports

  • Delete orders

Spring Security handles these restrictions using roles and authorities.

Creating In-Memory Users

For learning purposes, we will create users in memory.

@Configuration
public class UserConfig {

    @Bean
    public UserDetailsService userDetailsService() {

        UserDetails user = User.builder()
                .username("john")
                .password(passwordEncoder().encode("password"))
                .roles("USER")
                .build();

        UserDetails admin = User.builder()
                .username("admin")
                .password(passwordEncoder().encode("admin123"))
                .roles("ADMIN")
                .build();

        return new InMemoryUserDetailsManager(user, admin);
    }

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

}

Understanding the Code

UserDetails

Represents a user inside Spring Security.

It contains:

  • Username

  • Password

  • Roles

  • Authorities

UserDetailsService

Responsible for loading users.

Spring Security calls this service whenever a user tries to authenticate.

InMemoryUserDetailsManager

Stores users in memory.

Useful for:

  • Learning

  • Testing

  • Prototyping

Not recommended for production systems because users disappear after application restart.

PasswordEncoder

Passwords should never be stored in plain text.

We use BCrypt for hashing passwords.

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

Example:

Plain password:

password

Stored value:

$2a$10$P2P9P7j4t4Fj7e.....

Even if attackers gain database access, original passwords remain protected.

Creating Controller APIs

@RestController
@RequestMapping("/api")
public class EmployeeController {

    @GetMapping("/welcome")
    public String welcome() {
        return "Public API";
    }

    @GetMapping("/user")
    public String userApi() {
        return "User Dashboard";
    }

    @GetMapping("/admin")
    public String adminApi() {
        return "Admin Dashboard";
    }

}

Configuring Role-Based Access

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)
            throws Exception {

        return http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(auth -> auth

                        .requestMatchers("/api/welcome")
                        .permitAll()

                        .requestMatchers("/api/user")
                        .hasAnyRole("USER", "ADMIN")

                        .requestMatchers("/api/admin")
                        .hasRole("ADMIN")

                        .anyRequest()
                        .authenticated())

                .httpBasic(Customizer.withDefaults())
                .build();
    }

}

Understanding Role-Based Authorization

Public API

.requestMatchers("/api/welcome")
.permitAll()

Everyone can access this endpoint.

User API

.requestMatchers("/api/user")
.hasAnyRole("USER","ADMIN")

Accessible by:

  • USER

  • ADMIN

Admin API

.requestMatchers("/api/admin")
.hasRole("ADMIN")

Only ADMIN users can access this endpoint.

Testing APIs

Public Endpoint

GET /api/welcome

Response:

Public API

No authentication required.

User Endpoint

Login:

Username : john
Password : password

Request:

GET /api/user

Response:

User Dashboard

Admin Endpoint

Login:

Username : admin
Password : admin123

Request:

GET /api/admin

Response:

Admin Dashboard

Unauthorized Access

Suppose user "john" tries to access:

GET /api/admin

Spring Security returns:

403 Forbidden

This means:

  • User is authenticated.

  • User does not have sufficient permissions.

Internal Authentication Flow

Client
 ↓
Security Filter Chain
 ↓
Authentication Manager
 ↓
UserDetailsService
 ↓
PasswordEncoder
 ↓
Security Context
 ↓
Authorization
 ↓
Controller

The authenticated user information is stored inside the Security Context and is used during authorization checks.

Production-Level Best Practices

Never Store Plain Passwords

Always use:

BCryptPasswordEncoder

or stronger algorithms supported by Spring Security.

Avoid InMemoryUserDetailsManager

Production applications should load users from:

  • PostgreSQL

  • MySQL

  • MongoDB

  • LDAP

using a custom UserDetailsService.

Use the Principle of Least Privilege

Users should only receive permissions required to perform their tasks.

Avoid giving ADMIN privileges unnecessarily.

Separate Roles and Permissions

Large applications usually define:

Roles:

  • ADMIN

  • USER

  • MANAGER

Permissions:

  • READ_PRODUCTS

  • CREATE_PRODUCTS

  • DELETE_PRODUCTS

This provides better flexibility.

Use JWT for Stateless APIs

Modern microservices generally use:

  • JWT Authentication

  • OAuth2

  • OpenID Connect

instead of HTTP Basic Authentication.

Summary

In this article, we learned:

  • Authentication and Authorization

  • Their differences

  • UserDetails and UserDetailsService

  • InMemoryUserDetailsManager

  • PasswordEncoder and BCrypt

  • Role-based authorization

  • hasRole() and hasAnyRole()

  • Security flow inside Spring Security

  • Production-level recommendations

In Part 3, we will explore Password Encoding, BCryptPasswordEncoder, DelegatingPasswordEncoder, and password security best practices used in production systems.

Tags

Enjoyed this article?

Subscribe to our newsletter for more backend engineering insights and tutorials.