Spring Boot: From Basics to Production · Securing APIs with Spring Security
Method Security and Object-Level Authorization
Protect service methods with @PreAuthorize and ownership checks.
Enable @EnableMethodSecurity to secure service methods with @PreAuthorize SpEL expressions (hasRole, hasAuthority, or calls to a bean like @orderSecurity.canView(#id, authentication)). URL rules alone can't express object-level checks ("is this the user's order?"); do those in method security or services, and scope repository queries by owner/tenant.
@Configuration
@EnableMethodSecurity
class MethodSecurityConfig {}
@Component("orderSecurity")
class OrderSecurity {
private final OrderRepository orders;
OrderSecurity(OrderRepository orders) { this.orders = orders; }
boolean isOwner(long orderId, Authentication auth) {
return orders.existsByIdAndCustomerEmail(orderId, auth.getName());
}
}
@Service
class OrderQueries {
@PreAuthorize("hasRole('SUPPORT') or @orderSecurity.isOwner(#orderId, authentication)")
public OrderView get(long orderId) { /* ... */ }
@PreAuthorize("hasAuthority('SCOPE_orders:write')")
public void cancel(long orderId) { /* ... */ }
}
Common pitfalls
- Relying only on URL patterns, missing IDOR vulnerabilities.
- Self-invocation bypassing method security (proxy-based, like @Transactional).
- Returning 403 vs 404 inconsistently, leaking resource existence.
Key points
- @EnableMethodSecurity + @PreAuthorize
- Bean-based ownership checks
- Scope queries by owner/tenant
Further reading: Spring Security: Method security
Practice questions
Why aren't URL-based rules enough for authorization?
Answer
They can check roles per path but not whether a specific resource (order #42) belongs to the caller; object-level checks need the resource and the user.
Does @PreAuthorize work on a method called from the same class?
Answer
No. Like @Transactional, method security is applied via proxies, so internal self-calls bypass it.
Open in the app to mark lessons complete, take notes and track your progress.