Information Security 6 min read

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

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
&lt;/dependency&gt;
</code>

Custom User Configuration (application.yml)

<code>spring:
  security:
    user:
      name: admin
      password: 123456
</code>

Defining the Controller

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

    @PostMapping("post")
    public Object post() {
        return "demos post";
    }
}
</code>

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.

<code>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);
    }
}
</code>

Often developers disable CSRF for simplicity.

Disabling CSRF

<code>@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();
    }
}
</code>

Custom In‑Memory Authentication Configuration

<code>@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();
    }
}
</code>

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.

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

login 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.