<p><strike>I partially try to answer my question but It's still unclear to me why <code>session</code> table is used for storing user's session data too.</strike> For reference I use PostgreSQL database and &quot;<a href="https://craftcms.com/docs/4.x/config/#style-map-vs-fluent" rel="nofollow noreferrer">fluent</a>&quot; style declaration in my <em>general.php</em> file.</p>
<p>How session works depends on how you configure your session options in <em>config/general.php</em> file and certain directives in <em>php.ini</em> file.</p>
<p>Here's my testing configuration:</p>
<p><strong>config/general.php</strong></p>
<pre><code>// The amount of time before a user will get logged out due to inactivity
// 180 seconds or 3 minutes
-&gt;userSessionDuration(180)

// The amount of time a user’s elevated session will last, 
// which is required for some sensitive actions. 
// 0 to disable elevated session.
-&gt;elevatedSessionDuration(0)
</code></pre>
<p><strong>php.ini</strong></p>
<pre><code>; How long session cookie will be stored in browser. 0 until browser is restarted
session.cookie_lifetime = 0

; How long session data will be stored in Redis
session.gc_maxlifetime = 120
</code></pre>
<p><strong>How user's session is created</strong></p>
<ol>
<li><p>When successfully logged in to the control panel.</p>
<ul>
<li>A row with <code>id</code>, <code>userId</code>, <code>token</code>, <code>dateCreated</code>, <code>dateUpdated</code> and <code>uid</code> is created in <code>session</code> table in PostgreSQL database. These are required information for <code>users</code> table for example to look up a user and update <code>lastLoginDate</code> field which it's value would equal to <code>dateCreated</code> field from our <code>session</code> table</li>
<li>A key with value is created in Redis database which looks like the first picture in my question. If we would use <em>file</em> storage system for session instead of Redis than it's content is the same as the content saved in Redis database -&gt; <a href="https://nystudio107.com/blog/the-case-of-the-missing-php-session#once-more-unto-the-breach-dear-friends" rel="nofollow noreferrer">see example</a></li>
</ul>
</li>
</ol>
<p>Of course a cookie called whatever you set <code>phpSessionName</code> to is created in user's browser with encoded value which refers to I think <code>uid</code> field in <code>session</code> table. <a href="https://nystudio107.com/blog/the-case-of-the-missing-php-session" rel="nofollow noreferrer">This article</a> helped me before with some unclarities about session so I refer to it.</p>
<p><em>Note:</em> when you set <code>-&gt;userSessionDuration(0)</code>, Redis session key record doesn't contain <code>expire</code> and <code>duration</code> keys which means session exists as long as you keep the control panel opened. There's more to it which I explain bellow.</p>
<p><strong>How user's session behaves when logged in</strong></p>
<p><code>userSessionDuration</code> is the setting responsible for how long you stay logged in control panel. The <code>session.gc_maxlifetime</code> didn't play a big role in it unless it was set to less than 60 seconds. Apparently this is a time interval how often Craft CMS create <code>XHR</code> request in control panel. If <code>session.gc_maxlifetime = 10</code> than Redis session record would get removed and we got logged out after 10 seconds.</p>
<p>What I found out if user is logged in and not doing any requests:</p>
<ul>
<li>If <code>-&gt;userSessionDuration(0)</code> and <code>session.gc_maxlifetime = 120</code> than session record in Redis persists with <code>TTL</code> set to <code>120</code>. <code>TTL</code> resets back to <code>120</code> every 60 seconds because of a <code>XHR</code> request that Craft makes. Field <code>dateUpdated</code> in <code>session</code> table is also updated with a time of <code>XHR</code> request. So you stay logged in as long as you don't hit the button &quot;Log out&quot; or quit browser.</li>
<li>If <code>-&gt;userSessionDuration(180)</code> and <code>session.gc_maxlifetime = 120</code> than session record in Redis persists for 180 seconds with <code>TTL</code> set to <code>120</code> if not prolonged by hitting &quot;Keep me signed in&quot; button in control panel. <code>TTL</code> resets back to <code>120</code> every 60 seconds because of a <code>XHR</code> request that Craft makes. Field <code>dateUpdated</code> in <code>session</code> table is also updated with a time of <code>XHR</code> request. So you stay logged in for 180 seconds.</li>
</ul>
<p>So <a href="https://redis.io/commands/ttl/" rel="nofollow noreferrer">Redis key <code>TTL</code></a> (time to live) and <code>dateUpdated</code> in <code>session</code> table is something like <a href="https://www.poftut.com/what-is-mtime-in-linux-and-find-command/" rel="nofollow noreferrer"><code>mtime</code>in PHP session file</a>.</p>
<p><strong>How user's session is destroyed</strong></p>
<ol>
<li>When you log out from the control panel. Both records from PostgreSQL and Redis are removed.</li>
<li>When <code>-&gt;userSessionDuration(180)</code> is reached. Both records from PostgreSQL and Redis are removed.</li>
<li>When <code>-&gt;userSessionDuration(0)</code>, <code>session.gc_maxlifetime = 120</code> and you quit browser. That is when <code>session.gc_maxlifetime = 120</code> kicks in because there are no requests incoming to update times in both records and Craft removes a session record from Redis database only. This is unexpected behavior. A record in <code>session</code> table stays even if <code>purgeStaleUserSessionDuration</code> time is reached. I still don't know why &quot;garbage collection&quot; didn't kicked in.</li>
</ol>
<p><strong>Sum up</strong></p>
<p>Values you set to in <code>userSessionDuration</code> and <code>session.gc_maxlifetime</code> settings are important to keep user logged in according to your needs. <code>dataUpdated</code> in <code>session</code> table and Redis key <code>TTL</code> are also important aspects of session's lifetime which depends on <code>userSessionDuration</code>, <code>session.gc_maxlifetime</code> and activity in the control panel. A session records in <code>session</code> table are used for example for looking up a user in <code>users</code> table with aim to update for example <code>lastLoginDate</code>.</p>

CC BY-SA 4.0
2022-10-03T10:10:49.153Z
2022-10-04T09:03:15.103Z
2022-10-04T09:03:15.103Z
Dominik Krulak
<p>Let's say I installed latest version of Craft CMS (4.2.5) with no plugins or modules or any file that could modify current user's session. Just plain Craft CMS.
When I went through records in Redis I could locate key with a value that matches <code>sessions</code> table for <code>token</code> field.</p>
<p><strong>Redis record</strong></p>
<p><a href="https://i.sstatic.net/mw4KI.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/mw4KI.png" alt="Redis record" /></a></p>
<p><strong>PostgreSQL record</strong>
<a href="https://i.sstatic.net/DaIOq.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/DaIOq.png" alt="enter image description here" /></a></p>
<p>If Craft CMS stores session information listed on the second picture like <code>id</code>, <code>userId</code>, <code>token</code> , etc. than what for we store the same token in Redis?</p>
<p>Honestly I thought Craft CMS will store all session related data in Redis only.</p>
<p>How does Craft CMS handles user's session with Redis? Why is relational database involved?</p>

<session><redis>
How does Craft CMS handle user's session with Redis
# How does Craft CMS handle user's session with Redis

(Asked by: username_0 on 2022-09-26)

Let's say I installed latest version of Craft CMS (4.2.5) with no plugins or modules or any file that could modify current user's session. Just plain Craft CMS.
When I went through records in Redis I could locate key with a value that matches `sessions` table for `token` field.

**Redis record**

[![Redis record](https://i.sstatic.net/mw4KI.png)](https://i.sstatic.net/mw4KI.png)

**PostgreSQL record**
[![enter image description here](https://i.sstatic.net/DaIOq.png)](https://i.sstatic.net/DaIOq.png)

If Craft CMS stores session information listed on the second picture like `id`, `userId`, `token` , etc. than what for we store the same token in Redis?

Honestly I thought Craft CMS will store all session related data in Redis only.

How does Craft CMS handles user's session with Redis? Why is relational database involved?

**Tags:** session, redis

---

## 1 answers

### Answer by username_0 on 2022-10-03. Score: 3

I partially try to answer my question but It's still unclear to me why session table is used for storing user's session data too. For reference I use PostgreSQL database and "fluent" style declaration in my general.php file.
How session works depends on how you configure your session options in config/general.php file and certain directives in php.ini file.
Here's my testing configuration:
config/general.php
// The amount of time before a user will get logged out due to inactivity
// 180 seconds or 3 minutes
->userSessionDuration(180)

// The amount of time a user’s elevated session will last, 
// which is required for some sensitive actions. 
// 0 to disable elevated session.
->elevatedSessionDuration(0)

php.ini
; How long session cookie will be stored in browser. 0 until browser is restarted
session.cookie_lifetime = 0

; How long session data will be stored in Redis
session.gc_maxlifetime = 120

How user's session is created

When successfully logged in to the control panel.

A row with id, userId, token, dateCreated, dateUpdated and uid is created in session table in PostgreSQL database. These are required information for users table for example to look up a user and update lastLoginDate field which it's value would equal to dateCreated field from our session table
A key with value is created in Redis database which looks like the first picture in my question. If we would use file storage system for session instead of Redis than it's content is the same as the content saved in Redis database -> see example



Of course a cookie called whatever you set phpSessionName to is created in user's browser with encoded value which refers to I think uid field in session table. This article helped me before with some unclarities about session so I refer to it.
Note: when you set ->userSessionDuration(0), Redis session key record doesn't contain expire and duration keys which means session exists as long as you keep the control panel opened. There's more to it which I explain bellow.
How user's session behaves when logged in
userSessionDuration is the setting responsible for how long you stay logged in control panel. The session.gc_maxlifetime didn't play a big role in it unless it was set to less than 60 seconds. Apparently this is a time interval how often Craft CMS create XHR request in control panel. If session.gc_maxlifetime = 10 than Redis session record would get removed and we got logged out after 10 seconds.
What I found out if user is logged in and not doing any requests:

If ->userSessionDuration(0) and session.gc_maxlifetime = 120 than session record in Redis persists with TTL set to 120. TTL resets back to 120 every 60 seconds because of a XHR request that Craft makes. Field dateUpdated in session table is also updated with a time of XHR request. So you stay logged in as long as you don't hit the button "Log out" or quit browser.
If ->userSessionDuration(180) and session.gc_maxlifetime = 120 than session record in Redis persists for 180 seconds with TTL set to 120 if not prolonged by hitting "Keep me signed in" button in control panel. TTL resets back to 120 every 60 seconds because of a XHR request that Craft makes. Field dateUpdated in session table is also updated with a time of XHR request. So you stay logged in for 180 seconds.

So Redis key TTL (time to live) and dateUpdated in session table is something like mtimein PHP session file.
How user's session is destroyed

When you log out from the control panel. Both records from PostgreSQL and Redis are removed.
When ->userSessionDuration(180) is reached. Both records from PostgreSQL and Redis are removed.
When ->userSessionDuration(0), session.gc_maxlifetime = 120 and you quit browser. That is when session.gc_maxlifetime = 120 kicks in because there are no requests incoming to update times in both records and Craft removes a session record from Redis database only. This is unexpected behavior. A record in session table stays even if purgeStaleUserSessionDuration time is reached. I still don't know why "garbage collection" didn't kicked in.

Sum up
Values you set to in userSessionDuration and session.gc_maxlifetime settings are important to keep user logged in according to your needs. dataUpdated in session table and Redis key TTL are also important aspects of session's lifetime which depends on userSessionDuration, session.gc_maxlifetime and activity in the control panel. A session records in session table are used for example for looking up a user in users table with aim to update for example lastLoginDate.


---

