Close

Spring MVC - Cookie handling

[Last Updated: Mar 18, 2026]

Reading cookies using @CookieValue

Annotation @CookieValue allows a handler method parameter to be mapped to the value of an Http Cookie.

Definition of CookieValue

Version: 7.0.6
 package org.springframework.web.bind.annotation;
 @Target(ElementType.PARAMETER)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface CookieValue {
     @AliasFor("name")
     String value() default ""; 1
     @AliasFor("value")
     String name() default ""; 2
     boolean required() default true; 3
     String defaultValue() default ValueConstants.DEFAULT_NONE; 4
 }
1Alias for #name.
2The name of the cookie to bind to. (Since 4.2)
3Whether the cookie is required.
4The default value to use as a fallback.


Reading Cookie Value

 ...
 import org.springframework.web.bind.annotation.CookieValue;
 ...
 @RequestMapping
 public String handleRequest (
                        @CookieValue(value = "myCookieName",
                                            defaultValue = "defaultCookieValue")
                        String cookieValue, Model model) {
        System.out.println(cookieValue);
        ......
        return "my-page";
 }

Like other scenarios, there's an automatic value type conversion. In above example the cookie value is mapped to String type.



Writing Cookies using HttpServletResponse

To write cookies we can use javax.servlet.http.HttpServletResponse:

   ...
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletResponse; 
   ...
  @RequestMapping
  public String handleRequest (HttpServletResponse response, Model model) {

        Cookie newCookie = new Cookie("testCookie", "testCookieValue");
        newCookie.setMaxAge(24 * 60 * 60);
        response.addCookie(newCookie);
        .......
        return "my-page";
  }

Writing Cookies using Spring 5+ ResponseCookie

package com.logicbig.example;

.....
import org.springframework.http.ResponseCookie;

@Controller
public class MyController {

    @RequestMapping("test")
    public String handleTestRequest(Model model,
                                    HttpServletRequest request,
                                    HttpServletResponse response) {

        ResponseCookie responseCookie = ResponseCookie.from("testCookie")
                                                      .value("testCookieValue")
                                                      .maxAge(Duration.ofDays(30))
                                                      .build();
        response.addHeader("Set-Cookie", responseCookie.toString());

        model.addAttribute("msg", "test method msg");
        return "my-page";
    }
    .............
}


Using HttpServletRequest to read Cookies:

Instead of using @CookieValue we can also use HttpServletRequest as handler parameter to iterate through or read cookie values.

       .....
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
       .... 
    @RequestMapping
    public String handleTestRequest (Model model,
                                     HttpServletRequest request){


        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            Arrays.stream(cookies)
                  .forEach(c -> System.out.println(c.getName() + "=" + c.getValue()));
        }
        .......
        return "my-page";
    }

In above example we can also use the static helper method to find a specific cookie: org.springframework.web.util.WebUtils#getCookie(HttpServletRequest request, String name)


Cookie Security Attributes

As of Spring 6 / Jakarta EE 9, these three attributes are considered table stakes for any production cookie. Use ResponseCookie to set them — the raw jakarta.servlet.http.Cookie API cannot express SameSite at all.

  • HttpOnly — prevents JavaScript from reading the cookie via document.cookie. Blocks the most common XSS-based session-hijacking vector. Should be on by default for any session or auth cookie.
  • Secure — instructs the browser to transmit the cookie only over HTTPS. Without this, the cookie is sent in plaintext over HTTP and is trivially intercepted. Always set in production; can be relaxed to false in local development only.
  • SameSite — controls whether the browser sends the cookie on cross-site requests. Two practical values:
    • SameSite=Strict — cookie is never sent on any cross-site request, including navigations from external links. Strongest CSRF protection, but breaks OAuth and SSO redirect flows that land the user on your domain from an external one.
    • SameSite=Lax — cookie is sent on top-level navigations (e.g. clicking a link) but not on sub-resource requests (images, iframes, fetch). A safe default for most apps; supported by all modern browsers.
    • SameSite=None — cookie is always sent cross-site. Requires Secure to be set or browsers will reject it. Use only for deliberate cross-site scenarios such as embedded widgets or third-party APIs.

A minimal secure cookie using ResponseCookie:

ResponseCookie cookie = ResponseCookie.from("testCookie", value)
    .httpOnly(true)
    .secure(true)
    .sameSite("Lax")
    .path("/")
    .maxAge(Duration.ofHours(1))
    .build();

response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());


Running Example

Run the web application by using embedded tomcat:

mvn clean jetty:run

Output in Browser



Unit Tests

package com.logicbig.example;

import jakarta.servlet.http.Cookie;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.context.WebApplicationContext;

import static org.assertj.core.api.Assertions.assertThat;

@SpringJUnitConfig(classes = MyWebConfig.class)
@WebAppConfiguration
public class ControllerTest {

    private final MockMvcTester mockMvcTester;

    @Autowired
    public ControllerTest(WebApplicationContext wac) {
        this.mockMvcTester = MockMvcTester.from(wac);
    }

    @Test
    void testExpectedCookie() {
        // Asserting a cookie returned by the server
        assertThat(mockMvcTester.get().uri("/test"))
                .hasStatusOk()
                .cookies()
                .hasValue("testCookie","testCookieValue" );
    }

    @Test
    void testCookieRequest() {
        String cookieValue = "myUnitTestCookie";
        Cookie requestCookie = new Cookie("testCookie", cookieValue);

        // Sending a cookie and asserting a Model attribute
        assertThat(mockMvcTester.get().uri("/test2")
                .cookie(requestCookie))
                .hasStatusOk()
                .model()
                .containsEntry("cookieValue", cookieValue);
    }
}
mvn test -Dtest="ControllerTest"

Output

$ mvn test -Dtest="ControllerTest"
[INFO] Scanning for projects...
[INFO]
[INFO] ------------< com.logicbig.example:spring-cookie-handling >-------------
[INFO] Building spring-cookie-handling 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ spring-cookie-handling ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\spring-cookie-handling\src\main\resources
[INFO]
[INFO] --- compiler:3.15.0:compile (default-compile) @ spring-cookie-handling ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ spring-cookie-handling ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\spring-cookie-handling\src\test\resources
[INFO]
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ spring-cookie-handling ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ spring-cookie-handling ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.ControllerTest
myUnitTestCookie
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.061 s -- in com.logicbig.example.ControllerTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.091 s
[INFO] Finished at: 2026-03-18T16:06:03+08:00
[INFO] ------------------------------------------------------------------------
INFO: Completed initialization in 2 ms
INFO: Completed initialization in 2 ms

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 7.0.6 (Spring Web MVC)
     Version Compatibility: 3.2.3.RELEASE - 7.0.6Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 3.2.3.RELEASE
    • 3.2.4.RELEASE
    • 3.2.5.RELEASE
    • 3.2.6.RELEASE
    • 3.2.7.RELEASE
    • 3.2.8.RELEASE
    • 3.2.9.RELEASE
    • 3.2.10.RELEASE
    • 3.2.11.RELEASE
    • 3.2.12.RELEASE
    • 3.2.13.RELEASE
    • 3.2.14.RELEASE
    • 3.2.15.RELEASE
    • 3.2.16.RELEASE
    • 3.2.17.RELEASE
    • 3.2.18.RELEASE
    • 4.0.0.RELEASE
    • 4.0.1.RELEASE
    • 4.0.2.RELEASE
    • 4.0.3.RELEASE
    • 4.0.4.RELEASE
    • 4.0.5.RELEASE
    • 4.0.6.RELEASE
    • 4.0.7.RELEASE
    • 4.0.8.RELEASE
    • 4.0.9.RELEASE
    • 4.1.0.RELEASE
    • 4.1.1.RELEASE
    • 4.1.2.RELEASE
    • 4.1.3.RELEASE
    • 4.1.4.RELEASE
    • 4.1.5.RELEASE
    • 4.1.6.RELEASE
    • 4.1.7.RELEASE
    • 4.1.8.RELEASE
    • 4.1.9.RELEASE
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • javax.servlet-api:4.x
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39
    • javax.* -> jakarta.*
      jakarta.servlet-api:6.x
      Java 17 min
    • 6.0.0
    • 6.0.1
    • 6.0.2
    • 6.0.3
    • 6.0.4
    • 6.0.5
    • 6.0.6
    • 6.0.7
    • 6.0.8
    • 6.0.9
    • 6.0.10
    • 6.0.11
    • 6.0.12
    • 6.0.13
    • 6.0.14
    • 6.0.15
    • 6.0.16
    • 6.0.17
    • 6.0.18
    • 6.0.19
    • 6.0.20
    • 6.0.21
    • 6.0.22
    • 6.0.23
    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 6.2.16
    • 6.2.17
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3
    • 7.0.4
    • 7.0.5
    • 7.0.6

    Versions in green have been tested.

  • jakarta.servlet-api 6.1.0 (Jakarta Servlet API documentation)
  • spring-test 7.0.6 (Spring TestContext Framework)
  • hamcrest 3.0 (Core API and libraries of hamcrest matcher framework)
  • assertj-core 3.26.3 (Rich and fluent assertions for testing in Java)
  • junit-jupiter-engine 6.0.3 (Module "junit-jupiter-engine" of JUnit)
  • JDK 25
  • Maven 3.9.11

Spring MVC - @CookieValue Examples Select All Download
  • spring-cookie-handling
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyController.java
          • webapp
            • WEB-INF
              • views
        • test
          • java
            • com
              • logicbig
                • example


    See Also

    Join