Session Handling in Lucee
Session Handling
How session handling works in Lucee - configuration, storage, and security.
Type
Lucee supports 2 session types:
jee- managed by the Servlet Engine (JSession)cfml- managed by Lucee
Configure in .CFConfig.json:
{
"sessionType": "cfml"
}
Or in Application.cfc:
this.sessionType="cfml";
This doc covers cfml sessions only. For jee, see the Java EE Session Documentation.
Enable Sessions
.CFConfig.json:
{
"sessionManagement": true
}
Or Application.cfc:
this.sessionManagement=true;
Sessions are enabled by default.
(Idle)Timeout
.CFConfig.json:
{
"sessionTimeout": "0,0,30,0"
}
Format is days,hours,minutes,seconds. In Application.cfc:
// Different ways to set a 30-minute timeout
this.sessionTimeout=createTimeSpan(0,0,30,0); // using createTimeSpan
this.sessionTimeout=1/24/2; // using day fractions
Storage
Default is memory - session stored in memory for its full life cycle.
.CFConfig.json:
{
"sessionStorage": "memory"
}
Or Application.cfc:
this.sessionStorage="memory";
For non-memory storage, sessions are kept in memory up to a minute (idle), then removed and loaded from storage on demand.
Storage options:
memory- server memory, best for single-servercookie- browser cookies. Removed in Lucee 7. Avoid for security reasons.file- local files. Good for dev, not for clusters.[datasource-name]- stores incf_session_datatable (auto-created). Requiresstorage=trueon datasource.[cache-name]- e.g. Redis, Memcached. Ideal for distributed systems.
Empty sessions (only default keys) aren't written to storage.
Distributed Storage
Configure how data syncs between local memory and storage.
.CFConfig.json:
{
"sessionCluster": false
}
Or Application.cfc:
this.sessionCluster=false;
false - local memory is authoritative:
- Storage only updated when data changes
- Best for single-server
- Minimizes storage I/O
true - external storage is source of truth:
- Session verified against storage at request start
- Ensures consistency across servers
- Use for clustered environments
Event Handlers
Application.cfc event handlers:
// Called when a new session is created
public void function onSessionStart() {
// Initialize session variables
session.created = now();
session.lastAccessed = now();
}
// Called when a session ends (timeout or invalidation)
public void function onSessionEnd(required struct sessionScope,
required struct applicationScope) {
// Clean up resources
var userId = sessionScope.user?.id ?: "unknown";
application.logger.info("Session ended for user #userId#");
}
Session Management Functions
Checking if a session exists
Use SessionExists() to check if a session exists (since 6.2.1).
Note: StructKeyExists() on the session scope triggers creating an empty session.
Invalidating a session
SessionInvalidate() terminates the session and removes all data. Useful for logout:
// During logout
public void function logout() {
// Log user activity before invalidating
logUserActivity(session.user.id, "logout");
SessionInvalidate();
// All session variables are now cleared
location(url="login.cfm", addToken=false);
}
Rotating session cookies
SessionRotate() creates a new session with fresh token, copies existing data, invalidates old token. Prevents session fixation:
// After successful authentication
if (authentication.success) {
// Create new session to prevent session fixation
SessionRotate();
// Set session data with new session ID
session.user = userDetails;
session.authenticated = true;
session.lastLogin = now();
}
Security
Sessions are linked via CFID (in URL or cookie). CFTOKEN exists only for ACF compatibility.
If CFID in the URL is allowed, Lucee checks URL first, then cookies. Since 6.1, URL-based CFID only accepted if session is active in memory (up to 1 minute with non-memory storage).
Since Lucee 9.0, CFID and CFTOKEN in the URL are not accepted by default, only cookies are used (see Breaking Changes between Lucee 8.0 and 9.0). To accept them again:
-Dlucee.cfid.url.allow=true
or:
LUCEE_CFID_URL_ALLOW=true
Before Lucee 9.0 the default was to accept them, block CFID in URL entirely (since 6.1, lucee.cfid.url.allow since 6.2.1.59):
-Dlucee.read.cfid.from.url=false
or:
LUCEE_READ_CFID_FROM_URL=false
Client Identification in CFID
Embed client info in CFID to prevent session hijacking:
-Dlucee.identify.client=true
or:
LUCEE_IDENTIFY_CLIENT=true
When enabled:
- CFID includes client identifier (based on User-Agent, or Accept header as fallback)
- Session from Client A can't easily be used by Client B
- Backward compatible with older CFID patterns
Session Change Detection
Memory-only sessions don't need change detection.
With sessionCluster=true or external storage, Lucee tracks changes to know when to update storage. With sessionCluster=false, memory is authoritative - external storage is just backup.
At request end, dirty sessions are written to storage. Empty sessions (no user-defined vars) aren't written - avoid StructKeyExists(), use SessionExists() instead.
Use SessionCommit() to force immediate write during request.
Prior to 6.2.4, change detection only checked top-level values. Nested changes or component changes weren't detected.
Avoid storing components in session - expensive to serialize/deserialize per request. Instead, store simple values and use a component wrapper that reads from session properties.
Best Practices
Lucee tries to avoid creating sessions whenever possible. It only creates a session when:
- Session data is read or written in the code
- A key in the session scope is checked
- The Application.cfc contains session listeners like "onSessionStart" or "onSessionEnd"
Use SessionExists() to check if a session has been created, using StructKeyExists() will create a session.
Best practices for session handling:
- Avoid unnecessary session creation by only accessing the session scope when needed
- Use appropriate storage mechanisms based on your deployment architecture
- Consider security implications when choosing between URL and cookie-based session tracking
- Implement session rotation after authentication state changes
- Set appropriate timeout values based on your application's requirements
- Avoid storing components in the session scope, store simple values
Since Lucee 6.2, empty sessions are only kept for up to a minute, independent of the storage used, to optimize resource usage.
Troubleshooting Sessions
Lucee has a scope.log which when set to DEBUG (default is ERROR) logs detailed session handling information.
See Troubleshooting Lucee Server problems for a guide on how to run Lucee with logging to the console.
Expired sessions aren't immediately purged - they're cleaned up by the background controller periodically. For testing short-term session expiry, use admin action="purgeExpiredSessions" (LDEV-4819).
<cfadmin action="purgeExpiredSessions"
type="server"
password="#password#">