Session cookies duration

Hi,

I know I can create my own session cookies and define the expiration date, but I would like to know if it is possible to set, via Lucee admin, the default duration of the session cookies created by SetClientCookies?

Thank you

You mean cookies which persist just for the life of the browser session?

My understanding (on phone) is there isn’t a way to do that, it’s either session or persistent with an expiration

Hi @Zackster,

In fact I’m talking about session cookies created by Lucee (CFID / CFTOKEN). In the application.cfc file, we can put <cfset THIS.SetClientCookies = true /> and Lucee will take care of creating the user’s session cookies. But by default it sets an expiration date in 2053 (30 years).

yes you can set the defaults in admin

but I think you mean, can we allow disable setting an expiry date, thus producing session cookies for cfml session cookies? (confusing overlap of terms here!)

On the capture and in my lucee admin, I do not see a field to change the lifespan of the session cookies. I’m not talking here about the duration of a session that expires after X period of inactivity (session timeout), but rather the expiration date of the cookies cfid and cftoken that are saved in the web browser.

When I look at the Network tab in the web browser, I see a response header like this :
Set-Cookie : cfid=XXXXXXXXXXXXXXXX;Path=/;Expires=Sat, 13-Sep-2053 21:07:18 UTC;HttpOnly.

So Lucee makes these cookies expire in 30 years by default. Not the session itself, but the cookie linked to the session.

I found this block of code in the Lucee source code in this file : Lucee-6.0\core\src\main\java\lucee\runtime\type\scope\CookieImpl.java

private void _addCookie(Key key, String value, int expires, boolean secure, String path, String domain, boolean httpOnly, boolean preserveCase, Boolean encode,
			short samesite) {
		String name = preserveCase ? key.getString() : key.getUpperString();

		// build the value
		StringBuilder sb = new StringBuilder();
		/* Name */ sb.append(enc(name)).append('=').append(encode == null ? enc(value) : enc(value, encode.booleanValue()));
		/* Path */sb.append(";Path=").append(enc(path));
		/* Domain */if (!StringUtil.isEmpty(domain)) sb.append(";Domain=").append(enc(domain));
		/* Expires */if (expires != EXPIRES_NULL) sb.append(";Expires=").append(DateTimeUtil.toHTTPTimeString(System.currentTimeMillis() + (expires * 1000L), false));
		/* Secure */if (secure) sb.append(";Secure");
		/* HTTPOnly */if (httpOnly) sb.append(";HttpOnly");
		String tmpSameSite = SessionCookieDataImpl.toSamesite(samesite);
		/* Samesite */if (!StringUtil.isEmpty(tmpSameSite, true)) sb.append(";SameSite").append('=').append(tmpSameSite);
		rsp.addHeader("Set-Cookie", sb.toString());

	}

and this

	// FUTURE add to interface
	public void setCookie(Collection.Key key, Object value, Object expires, boolean secure, String path, String domain, boolean httpOnly, boolean preserveCase, Boolean encode,
			short samesite) throws PageException {

		int exp = EXPIRES_NULL;

		// expires
		if (expires == null) {
			exp = EXPIRES_NULL;
		}
		else if (expires instanceof Date) {
			exp = toExpires((Date) expires);
		}
		else if (expires instanceof TimeSpan) {
			exp = toExpires((TimeSpan) expires);
		}
		else if (expires instanceof String) {
			exp = toExpires((String) expires);
		}
		else if (Decision.isNumber(expires)) {
			exp = toExpires(Caster.toDoubleValue(expires));

		}
		else {
			throw new ExpressionException("invalid type [" + Caster.toClassName(expires) + "] for expires");
		}

		_addCookie(key, Caster.toString(value), exp, secure, path, domain, httpOnly, preserveCase, encode, samesite);
		super.set(key, value);

	}

And this in PageContextImpl.java :

private void setClientCookies() {
		TimeSpan tsExpires = SessionCookieDataImpl.DEFAULT.getTimeout();
		String domain = PageContextUtil.getCookieDomain(this);
		boolean httpOnly = SessionCookieDataImpl.DEFAULT.isHttpOnly();
		boolean secure = SessionCookieDataImpl.DEFAULT.isSecure();
		short samesite = SessionCookieDataImpl.DEFAULT.getSamesite();
		String path = SessionCookieDataImpl.DEFAULT.getPath();

		ApplicationContext ac = getApplicationContext();

		if (ac instanceof ApplicationContextSupport) {
			ApplicationContextSupport acs = (ApplicationContextSupport) ac;
			SessionCookieData data = acs.getSessionCookie();
			if (data != null) {
				// expires
				TimeSpan ts = data.getTimeout();
				if (ts != null) tsExpires = ts;
				// httpOnly
				httpOnly = data.isHttpOnly();
				// secure
				secure = data.isSecure();
				// domain
				String tmp = data.getDomain();
				if (!StringUtil.isEmpty(tmp, true)) domain = tmp.trim();
				// samesite
				samesite = data.getSamesite();
				// path
				String tmp2 = data.getPath();
				if (!StringUtil.isEmpty(tmp2, true)) path = tmp2.trim();
			}
		}
		int expires;
		long tmp = tsExpires.getSeconds();
		if (Integer.MAX_VALUE < tmp) expires = Integer.MAX_VALUE;
		else expires = (int) tmp;

		((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cfid, cfid, expires, secure, path, domain, httpOnly, true, false, samesite);
		((CookieImpl) cookieScope()).setCookieEL(KeyConstants._cftoken, cftoken, expires, secure, path, domain, httpOnly, true, false, samesite);

	}

one a cookie is set, the server has no idea about the expires date set in the browser

initial request

subsequent requests have only the cookie value passed

it needs to be set in the future like that, other basically lucee would need to issue set cookies on every request in increase the session timeout as each request bumps the session expiry server side

I agree the default period is too long, chrome for example only allows 400 days

I can help here: this control of the session cookie timeout CAN in fact be controlled, a couple of ways.

First in code–in both Lucee and ACF–via the sessioncookie struct, which can be set in the this scope of application.cfc or as an attribute of cfapplication. See for instance, Application.cfc / <cfapplication> :: Lucee Documentation.

And as that (and the cf docs) indicate, the setting for number of days the cookie should last (when created) is sessioncookie.timeout. Further note that it indicates that using -1 will make the cookie be a browser “session cookie”, meaning it disappears on browser close.

Finally, the cf admin also lets one control this (at the bottom of the “memory variables” page, where the -1 would work also). All this was introduced with Cf10 (and then in Lucee), but it’s one of those things that even very experienced folks just have never come across–though it can indeed be pretty vital for some situations. :slight_smile:

And yep, it would be a nice addition to the Lucee admin, and I’m sure Zac would consider it an excellent example of a rather simple PR for someone to offer, especially if new to contributing. :slight_smile:

4 Likes

It works with the sessioncookie struct in the application.cfc! Just for testing, I used this in the application.cfc :

<cfset THIS.SetClientCookies = true />
<cfset THIS.SessionCookie = {
   'timeout' = 10
}>

and the session cookies will expire in 10 days instead of 30 years.

Thank you @carehart and @Zackster for your time!

Note : I can’t flag an answer as the solution anymore? I don’t see any button for that…

1 Like

Thanks for the update, and happy to have helped.

1 Like