Start Learning
Javaneer
Back to stage
Module 4·Security

Method Security, CORS & CSRF

@PreAuthorize for fine-grained rules, plus what CORS and CSRF are and how Spring handles them.

16 min readIntermediate
On this page

URL-based rules cover most access control, but sometimes a rule belongs on the method, close to the logic it protects. And two acronyms - CORS and CSRF - trip up nearly every web developer. This lesson finishes the Security module by tidying up all three.

Method security with @PreAuthorize

Enable it once, then annotate methods with an authorization expression that's checked before the method runs:

@Configuration
@EnableMethodSecurity          // turns on @PreAuthorize/@PostAuthorize
class MethodSecurityConfig {}
@Service
class BookService {

    @PreAuthorize("hasRole('LIBRARIAN')")
    public void delete(String isbn) { ... }        // 403 unless the caller is a LIBRARIAN

    @PreAuthorize("#memberId == authentication.principal.id or hasRole('LIBRARIAN')")
    public List<Loan> loansOf(Long memberId) { ... } // your own loans, or a librarian's view
}

The second example shows method security's real strength: expressions can reference method arguments and the current user, so you can enforce "a member may see only their own data" - a rule that URL matchers can't express.

URL rules for coarse, method rules for fine

Use authorizeHttpRequests for broad, endpoint-level rules (this path needs LIBRARIAN), and @PreAuthorize for fine-grained, data-aware rules (you may act only on your own records). They complement each other; you don't have to choose one.

CORS: who may call your API from a browser

CORS (Cross-Origin Resource Sharing) is a browser security feature. By default a web page at app.bookvault.dev cannot call an API at api.bookvault.dev (a different origin) unless the API explicitly allows it. You opt in per allowed origin:

http.cors(cors -> cors.configurationSource(request -> {
    var config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("https://app.bookvault.dev"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    return config;
}));

CORS isn't a lock on your API - it's the browser asking your API "may this website talk to you?" and honoring the answer. Non-browser clients ignore it entirely.

CSRF: and why you disabled it

CSRF (Cross-Site Request Forgery) tricks a logged-in user's browser into sending an unwanted request using their session cookie. Spring Security's CSRF protection defends session-cookie apps. But BookVault authenticates with a Bearer token, not a cookie the browser attaches automatically - so there's nothing for CSRF to exploit, which is exactly why you disabled CSRF for the stateless API earlier.

Keep CSRF on for cookie/session apps

Disabling CSRF is correct only for stateless, token-authenticated APIs. If you build a traditional server-rendered app that authenticates with a session cookie, leave CSRF protection enabled - it's a genuine defense there.

Own-data-only

BookVault must let a member view their own active loans but not anyone else's, while a LIBRARIAN may view any member's. A URL rule like hasRole('MEMBER') can't express "only your own." Which mechanism do you use, and roughly what expression enforces it?

What can @PreAuthorize express that URL-based (authorizeHttpRequests) rules cannot?

Key takeaways

  • @EnableMethodSecurity + @PreAuthorize put authorization on methods, checked before they run.
  • Method expressions can reference arguments and the current user, enabling fine-grained rules like 'only your own data' that URL matchers can't express.
  • Use URL rules for coarse endpoint access and method security for fine-grained, data-aware checks - they complement each other.
  • CORS is a browser feature: your API opts in to which cross-origin sites may call it; non-browser clients ignore it.
  • CSRF protection defends cookie/session apps; it's safe to disable only for stateless, Bearer-token APIs like BookVault.
Was this lesson helpful?
Edit this page on GitHub