Securing REST APIs Using Spring Security
Course: Advance Java Training
Topic: Securing REST APIs Using Spring Security
Course Link: Advance Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy
1. Introduction to REST API Security
A REST API allows applications to communicate over HTTP using methods such as GET, POST, PUT, PATCH, and DELETE. REST APIs are commonly used by web applications, mobile applications, microservices, and third-party integrations.
Because REST APIs can expose sensitive information and business operations, they must be protected against unauthorized access, credential theft, malicious requests, and data manipulation. Spring Security provides a comprehensive framework for implementing authentication, authorization, and other security controls in Spring Boot applications.
Securing a REST API means ensuring that only appropriate clients and users can access resources and perform permitted operations. For example, a customer may view their own orders, while an administrator may manage products and user accounts.
Why Is REST API Security Important?
- Prevents unauthorized users from accessing protected endpoints.
- Protects confidential information and personal data.
- Restricts sensitive operations according to roles and permissions.
- Helps defend against common web application attacks.
- Supports secure communication between frontend and backend systems.
- Provides consistent authentication and authorization policies.
- Helps maintain data integrity and application reliability.
2. Learning Objectives
After studying this topic, learners should be able to:
- Understand the fundamentals of REST API security.
- Configure Spring Security in a Spring Boot application.
- Secure endpoints using request authorization rules.
- Differentiate authentication from authorization.
- Configure HTTP Basic authentication for learning and testing.
- Understand JWT and OAuth 2.0 Bearer token authentication.
- Implement role-based access control.
- Understand CSRF, CORS, password hashing, and security headers.
- Handle unauthorized and forbidden requests appropriately.
- Test secured REST endpoints using automated tests and API tools.
3. Understanding Authentication and Authorization
Authentication and authorization are two fundamental parts of API security. They work together but solve different problems.
| Feature |
Authentication |
Authorization |
| Purpose |
Verifies the identity of a user or client. |
Determines which resources or actions are permitted. |
| Question answered |
Who are you? |
What are you allowed to do? |
| Example |
Validating a password or access token. |
Checking whether a user has the ADMIN role. |
| Spring Security concepts |
AuthenticationManager, AuthenticationProvider. |
Authorization rules, roles, authorities. |
For example, a user may successfully authenticate with a valid access token but still be denied access to an administrator-only endpoint. Authentication establishes identity; authorization determines access.
4. Common Security Threats for REST APIs
4.1 Unauthorized Access
Unauthorized access occurs when an API allows a user to access data or functionality without sufficient authentication or permission checks.
Prevention: Require authentication for protected endpoints and apply authorization rules to sensitive operations.
4.2 Broken Access Control
Broken access control occurs when users can access resources or perform operations outside their permitted scope. For example, changing an order ID in a request might expose another customer's order.
Prevention: Check both user permissions and resource ownership on the server. Authentication alone does not prove that a resource belongs to the current user.
4.3 Credential Exposure
Credentials may be exposed through insecure connections, application logs, source code, or incorrectly configured storage.
Prevention: Use HTTPS, securely store credentials, avoid logging secrets, and rotate compromised credentials promptly.
4.4 Cross-Site Request Forgery (CSRF)
CSRF can cause a browser to send an unwanted authenticated request to an application where the browser automatically attaches credentials, such as session cookies.
Prevention: Retain appropriate CSRF protection for cookie-based authentication. Disabling CSRF should be a deliberate decision based on the application's authentication model and deployment architecture.
4.5 Cross-Origin Resource Sharing (CORS) Misconfiguration
CORS controls which browser origins may read responses from an API. An overly permissive policy can expose data to untrusted websites when other security conditions permit access.
Prevention: Allow only the required origins, methods, and headers. CORS is not a replacement for authentication or authorization.
4.6 Injection and Invalid Input
Malicious or malformed input can exploit weaknesses in database queries, data binding, or business logic.
Prevention: Validate input, use parameterized database queries, enforce constraints, and avoid constructing database queries through unsafe string concatenation.
5. Spring Security Architecture for REST APIs
Spring Security integrates with the servlet request-processing pipeline through security filters. Before a protected request reaches a controller, the configured filter chain can process authentication, security context management, authorization, and other security checks.
Typical Request Flow
- A client sends an HTTP request to the REST API.
- The request passes through the servlet filter chain.
- Spring Security processes the configured security filters.
- The configured authentication mechanism validates the credentials or access token.
- The authenticated identity and authorities become available to security components.
- Authorization rules determine whether the request is permitted.
- If permitted, the request reaches the controller and application service.
- The application returns an HTTP response to the client.
If authentication fails or access is denied, the request is handled by the configured security exception-handling mechanism rather than being allowed to perform the protected operation.
Important Spring Security Components
| Component |
Purpose |
SecurityFilterChain |
Defines security filters and request security configuration. |
AuthenticationManager |
Coordinates authentication when that authentication flow uses it. |
AuthenticationProvider |
Performs a particular type of authentication. |
UserDetailsService |
Loads user details for username-and-password authentication. |
PasswordEncoder |
Encodes and verifies stored password hashes. |
SecurityContext |
Holds the current security authentication information. |
AuthorizationManager |
Evaluates whether a request or invocation is authorized. |
6. Setting Up a Spring Boot REST API Project
Create a Spring Boot project with the Spring Web and Spring Security dependencies. The Spring Security starter provides the core security framework and its integration with Spring Boot.
6.1 Maven Dependencies
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Use a Spring Boot version compatible with your Java version and allow its dependency management to select compatible Spring Security versions.
7. Creating a REST Controller
Before securing an API, create a controller with endpoints that return sample data. These endpoints will be used to demonstrate public and protected access.
package com.example.api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/public")
public String publicEndpoint() {
return "This endpoint is publicly accessible.";
}
@GetMapping("/user")
public String userEndpoint() {
return "Welcome to the protected user endpoint.";
}
@GetMapping("/admin")
public String adminEndpoint() {
return "Welcome to the administrator endpoint.";
}
}
The controller defines three endpoints. The security configuration will determine which users can access each endpoint.
8. Configuring Spring Security for REST APIs
In modern Spring Security applications, security rules are commonly configured using a SecurityFilterChain bean. The following example uses HTTP Basic authentication to demonstrate endpoint protection. HTTP Basic is useful for learning and controlled testing, but production APIs should use an authentication architecture appropriate to their clients and threat model.
8.1 Security Configuration
package com.example.api.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(
HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.requestMatchers("/api/admin").hasRole("ADMIN")
.requestMatchers("/api/user").hasAnyRole(
"USER", "ADMIN")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService(
PasswordEncoder passwordEncoder) {
UserDetails user = User.withUsername("apiuser")
.password(passwordEncoder.encode("changeThisUserPassword"))
.roles("USER")
.build();
UserDetails admin = User.withUsername("apiadmin")
.password(passwordEncoder.encode("changeThisAdminPassword"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Learning example: This configuration uses in-memory accounts and HTTP Basic authentication. Replace the example credentials and account storage before deployment. Never commit real credentials or use sample passwords in a production environment.
8.2 Explanation of the Configuration
@Configuration identifies a Spring configuration class.
SecurityFilterChain defines how HTTP requests are secured.
authorizeHttpRequests() specifies access rules for incoming requests.
requestMatchers() selects URL patterns.
permitAll() allows access without requiring authentication for the matching rule.
hasRole("ADMIN") restricts access to users with the ADMIN role.
hasAnyRole("USER", "ADMIN") permits users with either role.
authenticated() requires an authenticated identity.
httpBasic() enables HTTP Basic authentication.
BCryptPasswordEncoder provides password hashing and verification.
9. Understanding Role-Based API Authorization
Role-based authorization controls access according to a user's assigned role. For example, an application may define USER, ADMIN, and MANAGER roles.
| Endpoint |
Required Access |
Purpose |
/api/public |
Public |
General information. |
/api/user |
USER or ADMIN |
Protected user functionality. |
/api/admin |
ADMIN only |
Administrative functionality. |
Spring Security's default role convention uses the ROLE_ prefix. When using hasRole("ADMIN"), the corresponding authority is normally ROLE_ADMIN. When using hasAuthority(), the exact authority value must match.
10. Securing APIs with JWT Authentication
JSON Web Tokens (JWTs) are commonly used to secure REST APIs. A client obtains an access token from an authentication or authorization service and sends it with subsequent API requests.
A JWT commonly contains claims such as the issuer, subject, expiration time, and optionally roles or scopes. The API must validate the token before trusting its claims.
10.1 Typical JWT Request Flow
- The client authenticates with an identity provider or authorization server.
- The authorization server issues an access token.
- The client sends the token in the HTTP Authorization header.
- Spring Security validates the token according to the configured trust settings.
- The application uses validated identity and authorization information to evaluate access rules.
- The API returns the protected resource when access is allowed.
A typical request includes the following header:
Authorization: Bearer <access-token>
The placeholder represents an access token issued for the application. Do not send real access tokens in public logs, screenshots, or source code repositories.
10.2 Add the OAuth2 Resource Server Dependency
For JWT-based API authentication, add the Spring Boot OAuth2 Resource Server starter. It provides resource-server integration; JWT decoding and signature validation also require the relevant JOSE support, which is brought in by the standard starter setup.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
10.3 Configure JWT Validation
If an authorization server issues JWTs, configure the issuer URI supplied by that trusted provider.
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://idp.example.com/issuer
Replace the example URI with the actual issuer URI from the identity provider. The issuer must match the token's issuer claim, and the authorization server must provide the expected signing keys and metadata.
10.4 Configure a JWT-Protected API
package com.example.api.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.config.Customizer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class JwtSecurityConfig {
@Bean
public SecurityFilterChain apiSecurityFilterChain(
HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.requestMatchers("/api/admin/**")
.hasAuthority("SCOPE_api.admin")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 ->
oauth2.jwt(Customizer.withDefaults())
);
return http.build();
}
}
This example uses an authority convention such as SCOPE_api.admin for an authorization scope. The token must contain the appropriate scope, and Spring Security must map it to the expected authority. JWT scope mapping and role mapping are not interchangeable; configure the application according to the token claims and authorization server.
When configuring JWT authentication, the application should validate the token's signature, issuer, expiration, and other required claims. Merely decoding a JWT is not sufficient to trust it.
11. Understanding JWT Roles and Scopes
JWT access tokens can carry scopes or role information, depending on the identity provider and token design. Spring Security can convert recognized claims into authorities.
| Concept |
Example |
Typical Use |
| Scope |
api.read |
Represents permission to access a defined API capability. |
| Role |
ROLE_ADMIN |
Represents a broad user responsibility. |
| Subject |
user-123 |
Identifies the token subject. |
| Issuer |
https://idp.example.com/issuer |
Identifies the trusted token issuer. |
| Expiration |
exp claim |
Defines when a token expires. |
Do not assume that a token's custom role claim will automatically become a Spring Security role. If the provider uses a custom claim, configure a suitable authority converter and test the resulting authorities.
12. Understanding HTTP Status Codes in Secured APIs
REST APIs should return appropriate HTTP status codes when security checks fail.
| Status Code |
Meaning |
Typical Security Scenario |
| 200 OK |
Request succeeded. |
Authenticated user is permitted to read a resource. |
| 201 Created |
A resource was created. |
Authorized user successfully creates a record. |
| 400 Bad Request |
Request is invalid. |
Malformed or invalid input. |
| 401 Unauthorized |
Authentication is missing or invalid. |
Missing or invalid credentials, depending on configuration. |
| 403 Forbidden |
Access is not permitted. |
Authenticated user lacks required permission. |
| 404 Not Found |
Resource was not found or is intentionally concealed. |
Requested resource is unavailable. |
Although the status phrase is historically named “Unauthorized,” HTTP 401 is generally used for authentication challenges. HTTP 403 indicates that the server refuses the request. The exact response should follow the API's authentication mechanism and security design.
13. Configuring CORS for REST APIs
Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls whether frontend applications hosted on different origins can access an API. An origin includes the scheme, host, and port.
For example, a frontend hosted at https://app.example.com may need permission to call an API at https://api.example.com.
13.1 Example CORS Configuration
package com.example.api.config;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(
List.of("https://app.example.com"));
configuration.setAllowedMethods(
List.of("GET", "POST", "PUT", "PATCH", "DELETE"));
configuration.setAllowedHeaders(
List.of("Authorization", "Content-Type"));
configuration.setAllowCredentials(false);
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Enable CORS handling in the relevant security chain with http.cors(Customizer.withDefaults()) when using this configuration source. Replace the sample frontend origin with the actual trusted origin.
If cookies or other browser-managed credentials are required, configure credential support carefully and specify explicit trusted origins. Do not combine credentialed CORS requests with a wildcard origin.
14. Understanding CSRF Protection
Cross-Site Request Forgery (CSRF) is relevant when browsers automatically attach authentication credentials, particularly session cookies. An attacker may attempt to trick a logged-in user's browser into sending an unwanted state-changing request.
Spring Security enables CSRF protection by default for common servlet-based configurations. Whether CSRF should remain enabled depends on the API's authentication mechanism and how clients send credentials.
When Should CSRF Be Considered?
- Cookie or session-based authentication: CSRF protection is generally important for unsafe requests such as POST, PUT, PATCH, and DELETE.
- Bearer tokens supplied explicitly by clients: CSRF exposure may differ when credentials are not automatically attached by the browser, but XSS and token-storage risks remain.
- Mixed browser and API applications: Review the complete credential model before changing CSRF settings.
Do not disable CSRF protection simply because an endpoint is a REST API. Make the decision based on how authentication works and which clients access the API.
15. Password Hashing and Secure Credential Storage
Passwords should never be stored in plaintext. Spring Security provides the PasswordEncoder abstraction so applications can encode passwords during registration and verify submitted passwords during authentication.
15.1 BCrypt Password Encoder
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
When a user registers, encode the password before storing it. During authentication, Spring Security compares the submitted password against the stored encoded value using the configured encoder.
For a production application, select and configure an appropriate password-hashing strategy for the application's security requirements. Never use reversible encryption or plaintext storage as a substitute for password hashing.
16. Protecting Sensitive Service Methods
Request-level security protects URL patterns, while method-level security protects business operations. Both can be useful because a service method may be invoked from multiple controllers or other application components.
16.1 Enable Method Security
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
}
16.2 Apply Role Restrictions
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class AccountService {
@PreAuthorize("hasRole('ADMIN')")
public String deleteAccount(Long accountId) {
return "Account deletion requested for " + accountId;
}
@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER')")
public String viewAccountReport() {
return "Account report generated.";
}
}
The annotations above enforce role checks when these methods are invoked through Spring-managed security proxies. They do not replace resource ownership checks, validation, or business rules that the methods may also require.
17. Securing Resources and Checking Ownership
Role checks alone are not sufficient when users can access individual resources. An API should verify that the authenticated user has permission to access the specific resource requested.
For example, an endpoint such as GET /api/orders/125 should not return order 125 merely because the caller is authenticated. The service should check whether the order belongs to the current user or whether the user has an authorized administrative role.
Example Service Logic
public Order getOrderForUser(Long orderId, String username) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(
"Order not found"));
boolean isOwner = order.getCustomer()
.getUsername().equals(username);
if (!isOwner) {
throw new AccessDeniedException(
"You are not permitted to access this order");
}
return order;
}
This example illustrates an ownership check. A complete implementation should also handle authorized administrative access if required, avoid leaking sensitive resource information, and use suitable exception handling. The username must come from the authenticated server-side security context, not from an untrusted request parameter.
18. Adding Security Headers
HTTP security headers help browsers apply additional security restrictions. Spring Security provides support for common headers, including protections against content sniffing and frame-related attacks.
Security headers should be selected according to the application's architecture. For example, Content Security Policy (CSP) is often configured based on the scripts and resources a frontend actually needs.
http.headers(headers -> headers
.contentTypeOptions(Customizer.withDefaults())
.frameOptions(frame -> frame.deny())
);
Use headers that are compatible with the application. For example, denying framing is suitable for many applications, but embedded applications may require a more specific policy. Do not treat headers as a substitute for authentication, authorization, input validation, or secure transport.
19. Testing Secured REST APIs
Testing should verify both successful requests and security failures. A secured API should not only allow valid users but also consistently reject requests that lack the required credentials or permissions.
19.1 Test with Postman or a Similar API Client
- Start the Spring Boot application.
- Send a GET request to the public endpoint.
- Send a request to a protected endpoint without credentials.
- Repeat the request with valid credentials.
- Use a normal user to access the administrator endpoint.
- Verify that an administrator can access the administrator endpoint.
- Check the HTTP status code and response body for each request.
19.2 Example Requests
Public endpoint:
GET http://localhost:8080/api/public
Protected endpoint:
GET http://localhost:8080/api/user
Authorization: Basic <base64-encoded-credentials>
Administrator endpoint:
GET http://localhost:8080/api/admin
Authorization: Basic <base64-encoded-credentials>
For HTTP Basic authentication, API clients can encode credentials into the header automatically. Do not use real credentials over unencrypted HTTP outside a controlled local development environment.
19.3 Automated Testing with MockMvc
Spring Security's test support allows endpoint authorization to be tested without requiring a real login for every test. Add the Spring Security test dependency that matches the project's managed Spring Security version.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request
.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request
.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request
.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request
.SecurityMockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result
.MockMvcResultMatchers.status;
The static imports above illustrate the helpers available in Spring Security test support; use the request builders from org.springframework.test.web.servlet.request.MockMvcRequestBuilders in a complete test class.
@SpringBootTest
@AutoConfigureMockMvc
class ApiSecurityTest {
@Autowired
private MockMvc mockMvc;
@Test
void publicEndpointIsAccessible() throws Exception {
mockMvc.perform(
org.springframework.test.web.servlet.request
.MockMvcRequestBuilders.get("/api/public"))
.andExpect(status().isOk());
}
@Test
void userCannotAccessAdminEndpoint() throws Exception {
mockMvc.perform(
org.springframework.test.web.servlet.request
.MockMvcRequestBuilders.get("/api/admin")
.with(user("apiuser").roles("USER")))
.andExpect(status().isForbidden());
}
@Test
void adminCanAccessAdminEndpoint() throws Exception {
mockMvc.perform(
org.springframework.test.web.servlet.request
.MockMvcRequestBuilders.get("/api/admin")
.with(user("apiadmin").roles("ADMIN")))
.andExpect(status().isOk());
}
}
These tests demonstrate authorization behavior using mock authenticated users. They do not validate the application's real credential storage or JWT verification. Add integration tests for the actual authentication mechanism. The unauthenticated response may be 401 or a redirect depending on the configured authentication entry point.
20. Common REST API Security Problems
| Problem |
Possible Cause |
Solution |
| Protected endpoint is accessible without credentials. |
The endpoint is matched by a public rule or falls under an unexpected configuration. |
Review matcher order and ensure protected paths require authentication. |
| Valid user receives HTTP 403. |
The user lacks the required role or authority. |
Inspect the granted authorities and configured access rules. |
| JWT is rejected. |
Invalid signature, expired token, incorrect issuer, or incorrect audience validation. |
Check token validity and the resource server's trust configuration. |
| JWT roles are not recognized. |
The roles claim is not mapped to Spring Security authorities. |
Configure and test the appropriate JWT authority converter. |
| Browser cannot call the API. |
CORS configuration does not permit the origin, method, or header. |
Configure CORS for the actual trusted frontend origin. |
| POST request fails with a CSRF error. |
A required CSRF token is missing or invalid. |
Send a valid CSRF token or review whether CSRF protection is appropriate for the authentication model. |
| Password authentication fails. |
The stored password hash and configured encoder do not match. |
Verify password encoding and the user-details configuration. |
| User can access another user's record. |
The API checks authentication but not resource ownership. |
Enforce ownership and object-level authorization in the service layer. |
21. Best Practices for Securing REST APIs
- Use HTTPS: encrypt API traffic in transit.
- Choose an appropriate authentication mechanism: use an identity provider and OAuth 2.0 or OpenID Connect where appropriate for production systems.
- Validate access tokens: verify signature, issuer, expiry, and other required claims.
- Apply least privilege: grant only the roles and permissions required for each user or client.
- Protect every sensitive endpoint: do not rely on frontend restrictions.
- Check resource ownership: prevent users from accessing other users' data.
- Use secure password hashing: never store plaintext passwords.
- Configure CORS carefully: allow only required origins and methods.
- Review CSRF protection: especially when browser-managed cookies authenticate requests.
- Validate request data: use validation annotations, service-level checks, and parameterized database queries.
- Protect secrets: keep passwords, signing keys, and client secrets out of source control and logs.
- Handle errors safely: avoid exposing stack traces or internal implementation details.
- Rate-limit sensitive operations: apply suitable protections against brute-force attempts and abuse.
- Log security events: record relevant events while avoiding sensitive credentials and tokens.
- Test authorization: include both allowed and denied access scenarios in automated tests.
22. Practical Project: Secure Employee REST API
Create an employee management API using Spring Boot and Spring Security. The goal is to protect employee records according to user roles and permissions.
Project Requirements
- Create REST endpoints to list, retrieve, create, update, and delete employee records.
- Implement authentication with an appropriate mechanism.
- Define ADMIN, MANAGER, and USER roles.
- Allow ADMIN users to manage all employee records.
- Allow MANAGER users to access only approved management operations.
- Allow USER accounts to view their own profile.
- Use request-level authorization and method-level security where appropriate.
- Validate request bodies and handle exceptions consistently.
- Test unauthorized requests and forbidden operations.
- Document endpoints, authentication requirements, and expected response codes.
Suggested Endpoint Design
| HTTP Method |
Endpoint |
Access Rule |
Purpose |
| GET |
/api/employees |
ADMIN or MANAGER |
List employees. |
| GET |
/api/employees/{id} |
Authorized employee access |
Retrieve a specific employee. |
| POST |
/api/employees |
ADMIN or MANAGER |
Create an employee. |
| PUT |
/api/employees/{id} |
ADMIN or permitted MANAGER |
Update an employee. |
| DELETE |
/api/employees/{id} |
ADMIN |
Delete an employee. |
| GET |
/api/profile |
Authenticated user |
View the current user's profile. |
For endpoints that operate on individual employees, include object-level authorization checks in addition to role checks. The exact policy should reflect the application's business requirements.
23. Interview Questions and Answers
Q1. What is Spring Security?
Spring Security is a framework for implementing authentication, authorization, and other security protections in Spring applications.
Q2. How do you secure REST APIs in Spring Boot?
Configure a SecurityFilterChain, define authentication and authorization rules, validate credentials or access tokens, and apply appropriate protections such as CSRF handling, CORS configuration, and secure password storage.
Q3. What is the difference between HTTP 401 and HTTP 403?
HTTP 401 generally indicates that valid authentication is missing or has failed. HTTP 403 indicates that the request is not permitted under the applicable authorization rules.
Q4. What is JWT authentication?
JWT authentication uses a JSON Web Token as a credential. A resource server validates the token and uses trusted claims to establish identity and evaluate authorization.
Q5. What is the Authorization header?
It is an HTTP header used to send authentication credentials. Examples include Basic credentials and Bearer access tokens.
Q6. What is the purpose of SecurityFilterChain?
It defines the security filters and request-processing rules that apply to matching HTTP requests.
Q7. What is the difference between roles and authorities?
A role usually represents a broad category of access, while an authority is a granted security value that can represent a role or a more specific permission.
Q8. What is CORS?
CORS is a browser mechanism that controls whether a webpage from one origin can access resources from another origin. It does not replace API authentication.
Q9. When is CSRF protection important?
It is particularly important when browsers automatically attach authentication credentials, such as session cookies, to requests. The correct configuration depends on the authentication model.
Q10. Why is HTTPS necessary?
HTTPS encrypts communication between clients and servers, helping protect credentials, access tokens, and application data in transit.
Q11. How should passwords be stored?
Passwords should be stored using an appropriate password-hashing algorithm through a configured PasswordEncoder, never as plaintext.
Q12. Why are resource ownership checks necessary?
Role checks alone may not stop one user from accessing another user's data. Ownership checks ensure that the caller is authorized to access the particular resource.
24. Quick Revision Checklist
- REST APIs use HTTP methods to expose application resources.
- Authentication verifies identity; authorization checks access permissions.
SecurityFilterChain configures request security.
hasRole() and hasAuthority() can restrict endpoint access.
- JWT-based APIs commonly use Spring Security OAuth2 Resource Server support.
- JWT validation must include appropriate trust and expiry checks.
- CSRF and CORS address different security concerns.
- Passwords must be securely hashed.
- Use HTTP 401 and 403 appropriately for authentication and authorization failures.
- Verify resource ownership for user-specific records.
- Test both successful and rejected requests.
- Use HTTPS and follow the principle of least privilege.
25. Conclusion
Securing REST APIs using Spring Security is an essential skill for Java backend developers. Spring Security provides the components needed to enforce authentication, role-based authorization, token validation, and additional request protections in Spring Boot applications.
A secure API requires more than adding a security dependency. Developers must carefully configure access rules, validate credentials and tokens, protect sensitive resources, manage password storage, and test failure scenarios. Applying these practices helps create reliable APIs for web applications, mobile clients, and distributed systems.
To continue learning, explore the Advance Java Training course, register for a course demo, or visit the JustAcademy website.
26. Additional Learning Resources