Cookies

In case websites want clients to store data locally in the browser, e.g. encrypted credentials, cookies can be used. Servers can instruct browsers to store these key-value pairs using the Set-Cookie response header. The browser will then send these values with every subsequent request via the Cookie request header.

Setting cookies

If you just want to set a simple cookie with a key and value, you can do so using the setCookie() method of the HttpResponse object like this:

final HttpMaid httpMaid = anHttpMaid()
        .get("/set", (request, response) -> response.setCookie("myCookie", "foo"))
        .build();

To check if the correct cookie has been set, curl can be used to inspect the response:

curl -c - http://localhost:1337/set

This will yield a result similar to this with the cookie being listed at the end:

# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

localhost       FALSE   /       FALSE   0       myCookie        "foo"

Cookies can have properties. If you like to set them according to yours needs, call the setCookie() method with CookieBuilder.cookie() as parameter. This returns an object of type CookieBuilder which can be used to fully customize your cookie. It offers the following methods:

  • withExpiration() - instructs the browser to delete the cookie after the provided expiration date by setting the Expires cookie directive. Is not set by default, which will cause browsers to delete the cookie after the session ends.

  • withExpiresDirective() - same as withExpiration(), but allows to set the Expires directive in a low-level fashion by directly setting its string value.

  • withMaxAge() - instructs the browser to delete the cookie after the provided time has passed by setting the Max-Age cookie directive. Is not set by default, which will cause browsers to delete the cookie after the session ends.

  • withMaxAgeDirective() - same as withMaxAge(), but allows to set the Max-Age directive in a low-level fashion by directly setting its string value.

  • exposedToAllSubdomainsOf() - tells the browser to send the cookie with all requests to one of the specified domains (and their subdomains) by setting the Domain cookie directive. Is not set by default, which will cause the browser to send the cookie with requests to the domain from which the cookie has been set, but not subdomains of it. Note that most browsers will reject the cookie if the server from which the cookie is set is not included in the list.

  • withDomainDirective() - same as exposedToAllSubdomainsOf(), but allows to set the Domain directive in a low-level fashion by directly setting its string value.

  • exposedOnlyToSubpathsOf() - tells the browser to only send the cookie with requests to the provided (sub-)routes by setting the Path cookie directive. Is not set by default, which will cause the browser to send the cookie with every request, regardless of the route.

  • withPathDirective() - same as exposedOnlyToSubpathsOf(), but allows to set the Path directive in a low-level fashion by directly setting its string value.

  • thatIsOnlySentViaHttps() - instructs the browser to send the cookie only with requests that are https-secured by setting the Secure cookie directive. Is not set by default.

  • withSecureDirective() - exactly the same as thatIsOnlySentViaHttps().

  • thatIsNotAccessibleFromJavaScript() - instructs the browser to not send the cookie with JavaScript/AJAX requests by setting the HttpOnly cookie directive. Is not set by default.

  • withHttpOnlyDirective() - exactly the same as thatIsNotAccessibleFromJavaScript().

  • withSameSitePolicy() - tells the browsers whether the cookie can be sent with cross-origin requests by setting the SameSite cookie directive. Possible options are

    • STRICT - cross-origin requests will not include the cookie
    • LAX - only send the cookie on certain types of cross-origin requests (see here for more information)
    • NONE - send the cookie with every request

    Not set by default, which will cause most browsers to default to the NONE policy.

  • withSameSiteDirective() - same as withSameSitePolicy(), but allows to set the SameSite directive in a low-level fashion by directly setting its string value.

  • withDirective() - allows to set a custom cookie directive. When called with one parameter, the directive is inserted as-is. When called with two parameters, both parameters (key and value) are concatenated with an = and inserted.

The following example will set the myCookie cookie with a lifetime of two hours:

final HttpMaid httpMaid = anHttpMaid()
        .get("/setWithOptions", (request, response) -> response.setCookie(cookie("myCookie", "foo").withMaxAge(2, HOURS)))
        .build();

Using the curl command from above with the correct path curl -c - http://localhost:1337/setWithOptions will yield the following result with the a unix timestamp for the cookie’s expiring date:

# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

localhost       FALSE   /       FALSE   1576954804      myCookie        "foo"

Receiving cookies

To access the cookies that are sent with a request, the HttpRequest object offers the cookies() method:

final HttpMaid httpMaid = anHttpMaid()
        .get("/get", (request, response) -> {
            final String myCookie = request.cookies().getCookie("myCookie");
            response.setBody("Value was: " + myCookie);
        })
        .build();

Sending a cookie with value bob using curl curl -b "myCookie=bob" http://localhost:1337/get yields the expected response:

Value was: bob

Invalidating cookies

If you want to instruct the browser to delete a cookie, you can do so by setting the cookie again with an expiration date that has already passed and an empty value. HttpMaid offers the invalidateCookie method in the HttpResponse object to do exactly this.

final HttpMaid httpMaid = anHttpMaid()
        .get("/invalidate", (request, response) -> response.invalidateCookie("myCookie"))
        .build();