Spring Security URL and Method Authorization
Controlling access to APIs based on the requested URL and HTTP method is a common requirement in modern web applications. Let us delve into understanding how Spring Security enables URL and HTTP method-based authorization to secure web applications effectively.
1. What is Spring Security?
Spring Security is a powerful and highly customizable authentication and access-control framework for Java applications, especially those built with the Spring Framework. It provides comprehensive security services for both web and non-web applications. The framework enforces security policies by intercepting incoming HTTP requests and applying configured rules before passing the request to the application. Its modular design allows for easy integration and extension to meet specific security requirements. Spring Security is widely used in enterprise applications to implement login/logout functionality, access control, and protection against various types of attacks.
1.1 Key Features Include
- Support for multiple authentication mechanisms including username/password, LDAP, OAuth2, OpenID Connect, and custom implementations
- Fine-grained authorization capabilities based on user roles, authorities, request URL patterns, HTTP methods, and more
- Built-in protections against common vulnerabilities such as CSRF (Cross-Site Request Forgery), XSS (Cross-Site Scripting), clickjacking, and session fixation
- Integration with popular frontend clients and REST APIs, allowing token-based authentication using JWT (JSON Web Token)
- Support for method-level security using annotations like
@PreAuthorize,@Secured, and@RolesAllowed - Security context management to maintain user identity and roles throughout a session or request lifecycle
1.2 Best Practices and Common Pitfalls
- Don’t disable CSRF unless building a stateless API: Disabling CSRF on traditional apps can expose vulnerabilities.
- Use strong password encoders: Always hash passwords with
BCrypt,Argon2, orPBKDF2. - Separate security configuration per module: Keep security rules modular and aligned with application boundaries.
- Use HTTPS in production: To protect credentials and tokens in transit.
2. Code Example
Before we dive into the implementation, make sure your Spring Boot project includes the necessary dependencies for Spring Security and Spring Web. Let’s add the dependency to pom.xml to include Spring Security in our project.
<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>
These dependencies provide the necessary libraries to expose REST endpoints and apply security constraints. Now, let’s build a Spring Boot application that exposes three REST API endpoints with role-based access control.
- The
GET /api/usersendpoint can be accessed by users with either USER or ADMIN roles. - The
POST /api/usersendpoint is restricted to users with the ADMIN role only, allowing them to create new users. - The
DELETE /api/users/{id}endpoint is also limited to ADMIN users, enabling them to delete a user by their ID.
These endpoints demonstrate how to secure HTTP methods using Spring Security’s role-based authorization.
2.1 Create a Controller
The controller exposes the APIs we want to secure.
package com.example.demo.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public String getUsers() {
return "Fetching all users";
}
@PostMapping
public String createUser() {
return "User created";
}
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable String id) {
return "Deleted user with id: " + id;
}
}
The UserController class is annotated with @RestController, indicating that it is a RESTful web controller where each method returns a response body directly. The base URL for all endpoints in this class is set to /api/users using @RequestMapping. The getUsers() method is mapped to HTTP GET requests and returns a string indicating that all users are being fetched. The createUser() method handles HTTP POST requests and returns a message confirming user creation. The deleteUser(String id) method maps to HTTP DELETE requests with a dynamic path variable id and returns a message stating that the user with the specified ID has been deleted.
2.2 Configure Spring Security
Now, let’s define role-based access rules.
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/users").hasRole("ADMIN")
.requestMatchers("/api/users/**").hasRole("ADMIN")
.requestMatchers("/api/users", org.springframework.http.HttpMethod.GET.name()).hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
)
.httpBasic();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public org.springframework.security.core.userdetails.UserDetailsService users() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
return new org.springframework.security.provisioning.InMemoryUserDetailsManager(user, admin);
}
}
The SecurityConfig class is annotated with @Configuration, indicating that it defines Spring Security-related configuration. The filterChain(HttpSecurity http) method configures the security filter chain. It disables CSRF protection for simplicity, then sets up authorization rules: only users with the ADMIN role can access /api/users and /api/users/** for operations like POST or DELETE, while both ADMIN and USER roles are allowed to perform GET requests on /api/users. Any other request must be authenticated. The configuration also enables HTTP Basic authentication for login prompts via browser or tools like curl/Postman. The passwordEncoder() method defines a BCryptPasswordEncoder bean to securely hash passwords. The users() method sets up an in-memory user store with two users: one with the USER role and one with the ADMIN role, both having their passwords encoded using BCrypt. This setup is ideal for simple demos or testing environments.
2.3 Main Application Class
Now let’s add the main class to bootstrap the Spring Boot application.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The DemoApplication class is annotated with @SpringBootApplication, which combines @Configuration, @EnableAutoConfiguration, and @ComponentScan. This serves as the entry point of the Spring Boot application. The main method uses SpringApplication.run() to launch the application.
2.4 How to Run the Application
To run the Spring Boot application, follow these steps:
- Ensure you have Java 17+ and Maven installed on your system.
- Open a terminal and navigate to the project directory.
- Run
mvn clean installto build the project. - Then run
mvn spring-boot:runto start the application. - By default, the server will start at
http://localhost:8080.
2.4.1 Demo
You can now use Postman or curl to make authenticated HTTP requests to /api/users and verify access control as per the configured roles.
- GET /api/users using credentials
user:user123: Allowed: Returns 200 OK (access granted to USER role) - POST /api/users using credentials
user:user123: Denied: Returns 403 Forbidden (USER role not permitted) - POST /api/users using credentials
admin:admin123: Allowed: Returns 200 OK (ADMIN role has access) - DELETE /api/users/1 using credentials
admin:admin123: Allowed: Returns 200 OK (ADMIN role permitted to delete) - DELETE /api/users/1 using credentials
user:user123: Denied: Returns 403 Forbidden (USER role not authorized)
These test cases confirm that Spring Security is enforcing both role and HTTP method-based access control.
Sign up




