Spring Security @PreAuthorize Annotation for Method Security

Last Updated : 10 Nov, 2025

@PreAuthorize is a part of Spring Security’s method-level security framework. It allows specifying authorization logic directly on methods in controller or service classes using SpEL-based expressions.

The @PreAuthorize annotation works by evaluating a Spring Expression Language (SpEL) expression before executing the target method. If the expression evaluates to false, Spring Security throws an AccessDeniedException, preventing the method from running.

Example Definition:

Java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PreAuthorize {
    String value();
}

The value attribute accepts a SpEL expression that defines the security condition.

Common Use Cases

  • Restricting access based on roles or authorities.
  • Ensuring only authenticated users can access certain methods.
  • Controlling access dynamically using custom user attributes or method parameters.

Understanding SpEL (Spring Expression Language) in @PreAuthorize

SpEL enables writing flexible access control expressions. Common usage examples include:

  • hasRole('ROLE_ADMIN'): Grants access only to users having the specified role
  • hasAuthority('READ_PRIVILEGE'): Checks whether the user has a specific authority
  • isAuthenticated(): Ensures the user is authenticated (logged in)
  • #id == authentication.principal.id: Allows access only when the resource belongs to the currently logged-in user

How @PreAuthorize Works

When a method annotated with @PreAuthorize is invoked, Spring Security follows this flow:

1. User Authentication: The user is authenticated by Spring Security.

2. Expression Evaluation: The SpEL expression defined in the annotation is evaluated using the user’s roles, authorities, or authentication object.

3. Access Decision:

  • If the condition returns true, the method executes.
  • If false, an AccessDeniedException is thrown.

Implementation of @PreAuthorize in Spring Boot

Below is a step-by-step guide to implementing method-level security using @PreAuthorize in a Spring Boot application.

Step 1: Create a Spring Boot Project

Create a new Spring Boot project using Maven with the following options:

  • Name: spring-security-preauthorize
  • Dependencies: Spring Web, Spring Security, Lombok, DevTools
Project Metadata
Create Project

Step 2: Add Dependencies

Your pom.xml file should include:

XML
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

Project Structure

Project Folder Structure
Project structure

Step 3: Configure Application Properties

spring.application.name=spring-security-preauthorize

Step 4: Create the User Class

Java
package com.gfg.springsecuritypreauthorize;

public class User {
    private Long id;
    private String username;
    private String role;

    public User(Long id, String username, String role) {
        this.id = id;
        this.username = username;
        this.role = role;
    }

    public Long getId() {
        return id;
    }
    public String getUsername() {
        return username;
    }
    public String getRole() {
        return role;
    }
}

This simple User class models a user entity with fields for ID, username, and role.

Step 5: Create the UserService Class

Java
package com.gfg.springsecuritypreauthorize;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Returns a mock user
    public User getUser() {
        return new User(1L, "John Doe", "ROLE_USER");
    }
}

This service returns a mock user for demonstration. In real-world scenarios, it would fetch user data from a database.

Step 6: Configure Spring Security

Java
package com.gfg.springsecuritypreauthorize;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/user").hasRole("USER")
                .anyRequest().authenticated())
            .httpBasic();
        return http.build();
    }

    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        builder.inMemoryAuthentication()
               .withUser("user")
               .password(passwordEncoder().encode("password"))
               .roles("USER");
        return builder.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  • @EnableMethodSecurity(prePostEnabled = true) enables method-level annotations like @PreAuthorize.
  • A simple in-memory user user/password with role USER is configured.
  • Basic authentication is used for simplicity.

Step 7: Create the UserController Class

Java
package com.gfg.springsecuritypreauthorize;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    // Accessible only to users with ROLE_USER
    @PreAuthorize("hasRole('ROLE_USER')")
    @GetMapping("/user")
    public User getUser() {
        return userService.getUser();
    }
}

The @PreAuthorize("hasRole('ROLE_USER')") annotation ensures that only users with the role ROLE_USER can access the /user endpoint. If an unauthorized user attempts to call this method, an AccessDeniedException will be thrown.

Step 8: Main Application Class

Java
package com.gfg.springsecuritypreauthorize;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringSecurityPreauthorizeApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityPreauthorizeApplication.class, args);
    }
}

Step 9: Run the Application

Run the application using your IDE or Maven:

Application Runs
console output

By default, it runs on port 8080.

Step 10: Testing the Application

Use Basic Authentication to test the secured endpoint.

Request:

GET: http://localhost:8080/user

Credentials:

  • Username: user
  • Password: password

Response:

Postman UI
Response

If you try to access the endpoint without valid credentials or roles, you’ll receive Access Denied.

Comment

Explore