Mastering CSRF Protection in Spring Security with In‑Memory Users

This tutorial walks through configuring Spring Security 5.4 on Spring Boot 2.4, demonstrating how to set up in‑memory user credentials, handle CSRF tokens during GET and POST requests, and customize the security filter chain to enable or disable CSRF protection.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering CSRF Protection in Spring Security with In‑Memory Users

Environment: Spring Boot 2.4.12 + Spring Security 5.4.9.

Adding the Dependency

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Custom User Configuration (application.yml)

spring:
  security:
    user:
      name: admin
      password: 123456

Defining the Controller

@RestController
@RequestMapping("/demos")
public class DemoController {
    @GetMapping("home")
    public Object home() {
        return "demos home";
    }

    @PostMapping("post")
    public Object post() {
        return "demos post";
    }
}

Access http://localhost:8080/demos/home – you will be redirected to the default login page.

Log in with the credentials defined above (admin/123456).

Testing POST Endpoint

When calling the POST endpoint via Postman, you must first log in through /login . After a successful login, the GET endpoint works, but the POST request returns 403 because the CSRF token is missing.

The login page includes a hidden _csrf field. If you submit a POST request without this field, authentication fails.

Include the _csrf parameter in your POST request to succeed.

How CSRF Protection Works

Spring Security adds a CsrfFilter that retrieves a token from the session (or generates one) and validates it on state‑changing requests.

public final class CsrfFilter extends OncePerRequestFilter {
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        CsrfToken csrfToken = this.tokenRepository.loadToken(request);
        boolean missingToken = (csrfToken == null);
        if (missingToken) {
            csrfToken = this.tokenRepository.generateToken(request);
            this.tokenRepository.saveToken(csrfToken, request, response);
        }
        if (!this.requireCsrfProtectionMatcher.matches(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        String actualToken = request.getHeader(csrfToken.getHeaderName());
        if (actualToken == null) {
            actualToken = request.getParameter(csrfToken.getParameterName());
        }
        if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
            AccessDeniedException exception = (!missingToken)
                ? new InvalidCsrfTokenException(csrfToken, actualToken)
                : new MissingCsrfTokenException(actualToken);
            this.accessDeniedHandler.handle(request, response, exception);
            return;
        }
        filterChain.doFilter(request, response);
    }
}

Often developers disable CSRF for simplicity.

Disabling CSRF

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Disable CSRF filter
        http.csrf().disable();
        // Require authentication for any request
        http.authorizeRequests().anyRequest().authenticated();
        // Enable default login page
        http.formLogin();
    }
}

Custom In‑Memory Authentication Configuration

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @SuppressWarnings("deprecation")
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // Define user, password and role
        auth.inMemoryAuthentication()
            .passwordEncoder(NoOpPasswordEncoder.getInstance())
            .withUser("guest").password("123456").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().anyRequest().authenticated();
        http.formLogin();
    }
}

After applying this configuration, authentication uses the defined in‑memory user.

The article ends here; the next part will cover request‑interception rules and custom login pages.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaSpring BootCSRFspring-securityIn-Memory Authentication
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.