Customizing spring Session Cookies
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.
Customizing Cookie behaviour
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.
- Bring in
org.springframework.session:spring-session-core
dependency. - Annotate the main class with
@EnableSpringHttpSession
- Supply a
SessionRepository<MapSession>
repository bean. I usedMapSessionRepository
for this example. -
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