4 min read

Customizing spring Session Cookies

December 30, 2020

By convention, most of the java web application use JSESSIONID as the cookie name to store the session key. In this post, We will see how this cookie behaviour can be changed.

Typical behaviour

In session based authentications like Form-Login and CAS(Central Authentication System), the session is established via cookies. This is done by sending a Set-Cookie header after a successful login similar to the one shown below.

Set-Cookie: JSESSIONID=6A55DBAF1A3BF1D938179C0D2E1CAA07; Path=/; HttpOnly

Once the browser reads this response header, it will add the value to its cookie storage with the name JSESSIONID. Along with the cookie value there are few other settings are hinted by the server. For example, the cookie is valid for all the urls under the path ’/‘. The cookie is marked as HttpOnly so that javascript cannot read these using document.cookies.

Why should we?

You may wonder why should you change the default cookie behaviour. Honestly, most of you don’t need to. However, When you run your applications behind load balancers, the same cookie name cannot be used across different applications. Also, the default behaviour is no timeout for these cookies.

Cookies set for subdomains cannot be read by parent domain (But the otherwise is true). For example, you may be running your APIs at api.somedomain.com and the frontend is at somedomain.com. In this case, you need to explicitly set the cookie domain to somedomain.com. Similarly, cookies set for specific path takes higher precedence. For instance, You may have configured your application to listen at the path /my-app. But this makes the cookie to also be set to /my-app. To keep the cookie to root path ’/’ or any different path, you need to customize the cookie.

Add the following configuration to your application.properties to change the behaviour.

To change the cookie name,

server.servlet.session.cookie.name=CUSTOMSESSIONID

To change the path of the cookie, use the following property.

server.servlet.session.cookie.path=/

To make sure javascript in your frontend can access the cookies, set the server.servlet.session.cookie.http-only property to false. This is usually not advised as attackers may try to XSS your web pages.

server.servlet.session.cookie.http-only=false

To change the cookie domain use server.servlet.session.cookie.domain property.

server.servlet.session.cookie.domain=somedomain.com

To make sure only secure(HTTPS) requests use the cookie set the server.servlet.session.cookie.secure property to true. This configuration is advised for added security.

server.servlet.session.cookie.secure=true

Occasionally, you can change the cookie’s expiration time using the server.servlet.session.cookie.max-age configuration. It takes a duration as parameter. For example, the following sets the expiration to 30 minutes. After this said duration, the browser would delete the cookie automatically. Note that this is different from server.servlet.session.timeout.

server.servlet.session.cookie.max-age=30M

With all the above setup done, the cookie would look something like below.

Set-Cookie: CUSTOMSESSIONID=A24225F633D2AA68C7D722D77C53943B; Max-Age=1800; Expires=Wed, 30-Dec-2020 14:28:13 GMT; Domain=somedomain.com; Path=/; Secure

Alternate approach using Java Configuration

All the above properties are auto-configured to a simple cookie implementation. However, there are attributes like SameSite ,DomainPattern etc cannot be done using just the configuration entries. To do these, you need make the following changes.

  1. Bring in org.springframework.session:spring-session-core dependency.
  2. Annotate the main class with @EnableSpringHttpSession
  3. Supply a SessionRepository<MapSession> repository bean. I used MapSessionRepository for this example.
  4. Define a CookieSerializer bean.

    @Bean
    CookieSerializer cookieSerializer() {
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        defaultCookieSerializer.setCookieName("CUSTOMSESSIONID");
        defaultCookieSerializer.setUseHttpOnlyCookie(false);
        defaultCookieSerializer.setCookiePath("/");
        defaultCookieSerializer.setDomainName("somedomain.com");
        defaultCookieSerializer.setUseSecureCookie(true);
        defaultCookieSerializer.sameSite("none");
        return defaultCookieSerializer;
    }

Even though the above is possible, the ones from configuration properties is enough to handle real-world cases. Also, The ideal way to do the java config is along with a dedicated session-store like Hazelcast or Redis. As these starters would bring in spring-session-core as a transitive dependency.

The code is available in the github link below. Start the app and try running the following curl and you will see the changes.

$ curl -i -u "user1:user1" http://localhost:8080/my-app/user