Skip to main content

Overview

Authorization in the User Management System is implemented using Spring Security’s role-based access control (RBAC). After a user is authenticated via JWT, their role determines which endpoints they can access.

Role-Based Access Control (RBAC)

The system uses two primary roles:
  • ROLE_USER: Standard user with access to basic user operations
  • ROLE_ADMIN: Administrator with elevated privileges

How RBAC Works

Authorization happens after authentication. The JwtAuthenticationFilter first validates the token and extracts the user’s role, then Spring Security’s authorization mechanism checks if that role has permission to access the requested endpoint.

Protected Endpoints

Endpoint protection is configured in SecurityConfig.java:27-31 using Spring Security’s authorizeHttpRequests DSL:
.authorizeHttpRequests(authz -> authz
        .requestMatchers("/auth/**").permitAll()
        .requestMatchers("/users/me").hasAnyAuthority("ROLE_USER")
        .requestMatchers("/admin/users").hasAnyAuthority("ROLE_ADMIN")
)

Endpoint Access Requirements

EndpointMethodRequired RoleDescription
/auth/signupPOSTNone (Public)Register a new user
/auth/loginPOSTNone (Public)Authenticate and receive JWT token
/users/meGETROLE_USERGet current user information
/admin/usersGETROLE_ADMINList all users (admin only)
The /users/me endpoint requires ROLE_USER, which means both regular users and admins can access it (since admins typically also have user permissions in many systems). However, based on this configuration, only users with exactly ROLE_USER can access it.

How Spring Security Enforces Authorization

Spring Security enforces authorization through a series of filters and security interceptors. Here’s the complete flow:

1. JWT Authentication Filter

The JwtAuthenticationFilter runs first and extracts the role from the JWT token (JwtAuthenticationFilter.java:33):
String role = jwtUtil.getRoleFromToken(token);
It then creates an authentication object with the role as a GrantedAuthority (JwtAuthenticationFilter.java:35-39):
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
        username,
        null,
        Collections.singletonList(new SimpleGrantedAuthority(role))
);

2. Security Context

The authentication object is stored in Spring Security’s SecurityContextHolder (JwtAuthenticationFilter.java:41):
SecurityContextHolder.getContext().setAuthentication(authToken);
This makes the authentication information available throughout the request lifecycle.

3. Authorization Decision

When the request reaches a protected endpoint, Spring Security’s AuthorizationFilter checks if the user’s authorities match the required authorities for that endpoint. For example, when accessing /admin/users:
  1. Spring Security retrieves the authentication from SecurityContextHolder
  2. It extracts the GrantedAuthority list (containing the role)
  3. It compares against the required authority: ROLE_ADMIN
  4. If the role matches, access is granted; otherwise, a 403 Forbidden response is returned

Filter Chain Order

The JwtAuthenticationFilter is added before Spring Security’s default authentication filter (SecurityConfig.java:32):
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
This ensures JWT validation happens first in the filter chain.

Authorization vs Authentication

It’s important to understand the difference:

Authentication

Who are you?Verifies the user’s identity through JWT token validation. Handled by JwtAuthenticationFilter.

Authorization

What can you do?Determines if the authenticated user has permission to access a resource. Handled by Spring Security’s authorization filters.

Stateless Authorization

The system uses stateless authorization, meaning:
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
Benefits:
  • No server-side session storage required
  • Better scalability (no session replication needed)
  • Each request is self-contained
Implications:
  • The JWT token must be included in every request
  • Role changes require a new token to be issued
  • Token expiration cannot be revoked server-side without additional mechanisms

Access Denied Scenarios

401 Unauthorized

Returned when:
  • No JWT token is provided
  • JWT token is invalid or expired
  • JWT token has an incorrect signature
# Missing token
curl -X GET http://localhost:8080/users/me
# Response: 401 Unauthorized

403 Forbidden

Returned when:
  • User is authenticated but lacks the required role
  • For example, a ROLE_USER trying to access /admin/users
# User with ROLE_USER trying to access admin endpoint
curl -X GET http://localhost:8080/admin/users \
  -H "Authorization: Bearer <user_token>"
# Response: 403 Forbidden
Make sure your client application handles both 401 and 403 responses appropriately. A 401 should typically trigger a login flow, while a 403 should show an “access denied” message.

Security Best Practices

1. Principle of Least Privilege

Users should be assigned the minimum role necessary for their tasks. By default, new users are assigned ROLE_USER (see User.java:33):
@Builder.Default
private Role role = Role.ROLE_USER;

2. Role Validation

Roles are stored as an enum (Role.java) to prevent invalid role values:
public enum Role {
    ROLE_USER,
    ROLE_ADMIN
}

3. Secure Defaults

The security configuration denies access to all endpoints by default unless explicitly permitted:
.authorizeHttpRequests(authz -> authz
        .requestMatchers("/auth/**").permitAll()
        // Only specific endpoints are configured
        // All others require authentication by default
)

Example: Admin Access Flow

Here’s how an admin accesses the user list:
1

Admin Login

Admin logs in with credentials and receives a JWT token containing ROLE_ADMIN.
2

Request with Token

Admin sends a GET request to /admin/users with the token in the Authorization header.
3

Token Validation

JwtAuthenticationFilter validates the token and extracts ROLE_ADMIN.
4

Authorization Check

Spring Security checks that the endpoint requires ROLE_ADMIN and the user has it.
5

Access Granted

The request proceeds to the UserController.getAllUsers() method.
6

Response

The list of all users is returned to the admin.

Controller Implementation

The controllers don’t need to manually check roles—Spring Security handles it automatically:

User Endpoint

// UserController.java:23-27
@GetMapping("/users/me")
@ResponseStatus(HttpStatus.OK)
public UserInfoResponseDTO info(@Valid @RequestBody UserInfoDTO userInfoDTO) {
    return userService.infoUSer(userInfoDTO.getEmail(), userInfoDTO.getPassword());
}

Admin Endpoint

// UserController.java:29-33
@GetMapping("/admin/users")
@ResponseStatus(HttpStatus.OK)
public List<User> getAllUsers() {
    return userService.findAll();
}
Notice that the controller methods don’t contain any authorization logic. The security configuration in SecurityConfig handles all authorization concerns, keeping the controller code clean and focused on business logic.

Testing Authorization

Testing User Access

# Login as a regular user
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "password123"}'

# Use the token to access user endpoint (should succeed)
curl -X GET http://localhost:8080/users/me \
  -H "Authorization: Bearer <user_token>" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "password123"}'

# Try to access admin endpoint (should fail with 403)
curl -X GET http://localhost:8080/admin/users \
  -H "Authorization: Bearer <user_token>"

Testing Admin Access

# Login as admin
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "adminpass"}'

# Access admin endpoint (should succeed)
curl -X GET http://localhost:8080/admin/users \
  -H "Authorization: Bearer <admin_token>"

Next Steps

Roles

Learn about specific roles and their permissions

Authentication

Understand how JWT authentication works

Build docs developers (and LLMs) love