In this post, We will take a look at Customizing Spring Session Cookies with an example.
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
Code language: JavaScript (javascript)
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 at 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 Customizing Spring Session Cookies?
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 the 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 a 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 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 spring session cookie name, use the following property.
server.servlet.session.cookie.name=CUSTOMSESSIONID
Code language: Properties (properties)
The following property will help you change the session cookie path.
server.servlet.session.cookie.path=/
Code language: Properties (properties)
To make sure javascript in your frontend can access the cookies, set the server.servlet.session.cookie.http-only
property to false
. Do not use this unless you understand the risks of getting XSS attacks.
server.servlet.session.cookie.http-only=false
Code language: Properties (properties)
To change the cookie domain use server.servlet.session.cookie.domain
property.
server.servlet.session.cookie.domain=somedomain.com
Code language: Properties (properties)
To make sure only secure(HTTPS) requests use the cookie set the server.servlet.session.cookie.secure
property to true
. For added security, make sure you use this.
server.servlet.session.cookie.secure=true
Code language: Properties (properties)
Occasionally, you can change the spring session cookie 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
Code language: Properties (properties)
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
Code language: JavaScript (javascript)
Provide a Cookie Serializer implementation
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 achieve that, you need to provide a CookieSerializer bean.
- 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 as shown below.
@Bean
CookieSerializer cookieSerializer() {
DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
defaultCookieSerializer.setCookieName("CUSTOMSESSIONID");
defaultCookieSerializer.setUseHttpOnlyCookie(false);
defaultCookieSerializer.setCookiePath("/");
defaultCookieSerializer.setDomainName("somedomain.com");
defaultCookieSerializer.setUseSecureCookie(true);
defaultCookieSerializer.setSameSite("none");
return defaultCookieSerializer;
}
Code language: Java (java)
Even though the above is possible, the ones from configuration properties are 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
Code language: Bash (bash)
You can find the samples for this post at this github repository.
You may also find the following articles related to this write-up.