Spring Security Role-Based Access Control (RBAC) Explained with Real-Time Examples

Introduction :

In modern applications, not every user should have access to every feature. For example, in a banking application, customers can view their accounts, employees can process requests, and administrators can manage users. Allowing all users to access all resources would be a serious security risk.

This is where Role-Based Access Control (RBAC) comes into the picture.

In this article, we'll understand RBAC in Spring Security, learn how roles work with JWT Authentication, and implement role-based authorization using real-time examples.

What is RBAC?

RBAC (Role-Based Access Control) is a security mechanism that restricts access to resources based on user roles.

Instead of assigning permissions individually to every user, users are assigned roles, and permissions are associated with those roles.


Common Roles in Applications

  • ADMIN

  • MANAGER

  • EMPLOYEE

  • USER

  • CUSTOMER

When a user logs in, the system checks their role and grants access only to the resources allowed for that role.

Authentication and Authorization

Many developers confuse these two concepts.

Authentication

Authentication verifies who the user is.

Example:

  • Username: Sulochana

  • Password: password123

If the credentials are correct, the user is authenticated.

Authorization

Authorization determines what the authenticated user can access.

Example:

  • ADMIN can manage users.

  • USER can view profile information.

  • MANAGER can approve requests.

JWT Authentication handles identity verification, while RBAC handles access control.

Real-Time Example

Let's consider an Online Banking Application.

CUSTOMER

Can:

  • View account details

  • Transfer money

  • View transaction history

Cannot:

  • Create new users

  • Access admin dashboard

EMPLOYEE

Can:

  • Verify customer requests

  • Process transactions

Cannot:

  • Manage system users

ADMIN

Can:

  • Create users

  • Delete users

  • Access admin dashboard

  • Manage application settings

RBAC ensures each user can access only the resources required for their job.

Step 1: Create Role Enum

First, define the available roles in the application.

public enum Role {
    USER,
    MANAGER,
    ADMIN
}

Using an Enum helps prevent typing mistakes and keeps role management consistent.

Why do we use Enum for Roles?

Instead of storing roles as plain strings:

private String role;

we use:

public enum Role {
USER,
MANAGER,
ADMIN
}

and then:

@Enumerated(EnumType.STRING)

private Role role;

1. Prevents Typing Mistakes

With String:

user.setRole("ADMIN");
user.setRole("admin");
user.setRole("Admin");
user.setRole("ADMN"); // typo

All of these compile successfully, which can cause authorization issues.

2. Improves Code Readability

String approach:

if(user.getRole().equals("ADMIN")) {

    // logic
}

Enum approach:

if(user.getRole() == Role.ADMIN) {

    // logic
}

Cleaner and easier to understand.

3. Better Maintainability

Suppose your application grows and you add:

public enum Role {

    USER,
MANAGER,
ADMIN,
SUPER_ADMIN
}

Now the role is available everywhere in the project automatically.

Step 2: Add Role to User Entity

Store the user's role in the database.

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    @Enumerated(EnumType.STRING)
    private Role role;
}

Why Use EnumType.STRING?

Good:

ADMIN
USER
MANAGER

Avoid:

0
1
2

Using strings makes database records easier to understand and maintain.

Step 3: Include Roles in UserDetails

Spring Security needs to know the user's authorities.

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {

    return List.of(
        new SimpleGrantedAuthority("ROLE_" + user.getRole().name())
    );
}

Example

If the user's role is:

ADMIN

Spring Security internally converts it to:

ROLE_ADMIN

This role will be used during authorization checks.

Step 4: Add Role Information to JWT Token

When generating the JWT token, include the user's role.

Map<String, Object> claims = new HashMap<>();
claims.put("role", user.getRole().name());

String token = jwtService.generateToken(claims, user);

Generated JWT Payload:

{
  "sub": "Sulochana",
  "role": "ADMIN"
}

Now the role information travels securely with every request.

Step 5: Configure Role-Based Access

Configure Spring Security to restrict API access.

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

    http
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth

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

            .requestMatchers("/manager/**")
            .hasRole("MANAGER")

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

            .anyRequest()
            .authenticated()
        );

    return http.build();
}

How This Works

ADMIN APIs

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

Only ADMIN users can access:

/admin/dashboard
/admin/users
/admin/settings

MANAGER APIs

.requestMatchers("/manager/**")
.hasRole("MANAGER")

Only MANAGER users can access:

/manager/reports
/manager/approvals

USER APIs

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

Both USER and ADMIN can access:

/user/profile
/user/history

Step 6: Create Protected APIs

Admin Controller

@RestController
@RequestMapping("/admin")
public class AdminController {

    @GetMapping("/dashboard")
    public String dashboard() {
        return "Welcome Admin";
    }
}

User Controller

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/profile")
    public String profile() {
        return "User Profile";
    }
}

Testing with Postman

Login as USER

JWT Payload:

{
  "username":"Sulochana",
  "role":"USER"
}

Access:

GET /user/profile

Result:

200 OK

Access:

GET /admin/dashboard

Result:

403 Forbidden

Common Mistakes

1. Forgetting ROLE_ Prefix

Incorrect:

new SimpleGrantedAuthority("ADMIN")

Correct:

new SimpleGrantedAuthority("ROLE_ADMIN")

2. Not Including Roles in JWT

If roles are not present in the JWT token, authorization checks will fail.

3. Confusing Authentication and Authorization

Authentication:

Who are you?

Authorization:

What are you allowed to do?

4. Using hasRole() Incorrectly

Incorrect:

.hasRole("ROLE_ADMIN")

Correct:

.hasRole("ADMIN")

Spring automatically adds the ROLE_ prefix.

Interview Questions

1. What is RBAC?

RBAC is a security model that grants access to resources based on user roles.

2. What is the difference between Authentication and Authorization?

Authentication verifies identity, while authorization determines permissions.

3. Why do we use ROLE_ prefix in Spring Security?

Spring Security uses ROLE_ as the default prefix for role-based authorities.

4. What is the difference between hasRole() and hasAuthority()?

hasRole():

.hasRole("ADMIN")

Internally becomes:

ROLE_ADMIN

hasAuthority():

.hasAuthority("ROLE_ADMIN")

Requires the full authority name.

5. Why is RBAC important?

RBAC improves security, simplifies permission management, and ensures users can access only authorized resources.

Conclusion :

In this article, we learned how to implement Role-Based Access Control (RBAC) in Spring Security using JWT Authentication. We created roles, secured APIs based on user permissions, included roles inside JWT tokens, and restricted access using Spring Security configuration.

RBAC is one of the most important security concepts used in enterprise applications, banking systems, e-commerce platforms, and microservices architectures.

In the next article, we'll explore Method-Level Security using annotations such as @PreAuthorize, @PostAuthorize, and @Secured. We'll learn how to secure individual service and controller methods and implement fine-grained access control in Spring Boot applications.

Comments

Popular posts from this blog

React Basics – How to Create Component

How to Build REST API using Spring Boot (Step-by-Step Guide)

Spring Boot @RequestParam Annotation Explained with Real-Time Examples