How to protect Spring Boot endpoints with annotations
How annotations simplify permission checks in Spring Boot APIs, instead of scattering rules through the code.
Spring Security offers @PreAuthorize, but in multi-tenant products with dozens of permissions the code becomes duplicated magic strings. Domain annotations — tied to your IAM — make the intent explicit on the endpoint and centralize validation in an interceptor or filter.
A declarative approach
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}")
@GatekeeperProtected(permissions = "orders:read")
public Order get(@PathVariable UUID id) {
return orderService.find(id);
}
@DeleteMapping("/{id}")
@GatekeeperProtected(permissions = "orders:delete")
public void delete(@PathVariable UUID id) {
orderService.delete(id);
}
}The SDK aspect or filter runs before the method: it validates the JWT, reads permissions from the token, compares them with the annotation, and returns 403 if a permission is missing — or 401 if the token is invalid.
When to use annotations
- REST APIs whose actions map to permissions
- Teams that want access rules in the same file as the endpoint
- Products that already use an external IAM (Gatekeeper, Keycloak, and others)
Common mistakes
- An annotation only on the controller, forgetting endpoints in advice or WebFlux
- A permission that is too generic — a single ADMIN bypass
- Not testing the 401 and 403 cases in integration
- Mixing tenant logic and permission logic in the same if
How Gatekeeper ID helps
The Gatekeeper Spring Boot SDK provides @GatekeeperProtected integrated with JWT validation and the tenant configured in YAML. Permissions come from the console — changes do not require a redeploy.
RBAC foundations: RBAC in Java applications. A short guide is in the SDK documentation.
Conclusion
Annotations do not replace a solid IAM — but they remove repeated conditionals and document access at the right point. In Spring Boot, this is one of the most readable ways to scale authorization.