How to Fix Magento Login Issues with Cookies and Sessions
This article was created in partnership with Ktree. Thank you for supporting the partners who make SitePoint possible.
In this article are looking at how Magento cookies can create issues with the login functionality of both the customer-facing front-end and admin back-end, the reason it occurs and how it should be resolved.
This is also known as the looping issue, as the screen redirects itself to the same screen, even though the username and password is correct.
A script is provided at the end of the article which can help detect a few of the issues. Feel free to use and modify as per your needs.
What is a Cookie?
A cookie is a piece of text that a web server can store on a user’s hard drive, and can also later retrieve it. Magento uses cookies in Cart & Backend Admin functionalities, and they may be the source of a few problems when unable to login to Magento.
What is a Session?
A session is an array variable on the server side, which stores information to be used across multiple pages. For example, items added to the cart are typically saved in sessions, and when the user browses the checkout page they are read from the session.
Sessions are identified by a unique ID. Its name changes depemnding on the programming language — in PHP it is called a ‘PHP Session ID’. As you might have guessed, the same PHP Session ID needs to be stored as a cookie in the client browser to relate.
Magento’s storage of Sessions
Magento can store sessions via multiple session providers and this can be configured in the Magento config file at app/etc/local.xml
. These session providers can be chosen here.
File
<session_save><![CDATA[files]]></session_save>
<session_save_path>
<![CDATA[/tmp/session]]>
</session_save_path>
Database
Allowing sessions to store themselves in the database is done in /app/etc/local.xml
by adding <session_save><![CDATA[db]]></session_save>
.
Magento applications store sessions in the Core\_session
table.
Redis
<session_save>db</session_save>
<redis_session>
<host>127.0.0.1</host>
<port>6379</port>
</redis_session>
MemCache
session_save><![CDATA[memcache]]></session_save>
<session_save_path>
<![CDATA[tcp://localhost:11211?persistent=1&weight=2&timeout=10&retry_interval=10]]>
</session_save_path>
Magento Usage
Magento uses two different cookies named 'frontend' and 'adminhtml'. The first one is created when any page is browsed. The same cookie is also updated whenever the customer logs in, and the next one is created when a backend user is logged in. You can check whether the cookies have been created by clicking Inspect Element > Application, as in the below picture (from Chrome):
Cookies are configured in Magento via the Configuration admin menu – System > Configuration > General > Web.
Problem: Login Fails & Redirects to Login Page
If you haven’t experienced this problem, then you haven’t worked with Magento long enough!
This is how it typically happens: when you login by entering your username and password, you will be redirected to the same login page and URL, and your browser is appended with nonce id. This happens for both the customer front-end and the Magento back-end login.
Let's look at a few reasons why this happens, and how we should resolve those issues.
Reason #1: Cookie domain does not match server domain
Let’s say your Magento site is example.com
and the cookie domain in Magento is configured as xyz.com
.
In this scenario both Magento cookies will set Domain Value
as xyz.com
, but for validating the session Magento will consider the domain through which the site was accessed — in this case example.com
. Since it won’t be able to find an active session with the example.com
domain value, it will redirect the user to the login page even when valid credentials are provided.
app/code/core/Mage/Core/Model/Session/Abstract.php
After login or logout, the Magento system will regenerate the session using the following script:
public function renewSession()
{
$this->getCookie()->delete($this->getSessionName());
$this->regenerateSessionId();
$sessionHosts = $this->getSessionHosts();
$currentCookieDomain = $this->getCookie()->getDomain();
if (is_array($sessionHosts)) {
foreach (array_keys($sessionHosts) as $host) {
// Delete cookies with the same name for parent domains
if (strpos($currentCookieDomain, $host) > 0) {
$this->getCookie()->delete($this->getSessionName(), null, $host);
}
}
}
return $this;
}
app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
Magento will validate the session for every request with the following method:
public function init($namespace, $sessionName=null)
{
if (!isset($_SESSION)) {
$this->start($sessionName);
}
if (!isset($_SESSION[$namespace])) {
$_SESSION[$namespace] = array();
}
$this->_data = &$_SESSION[$namespace];
$this->validate();
$this->revalidateCookie();
return $this;
}
You may normally see this when you migrate your Magento instance from one domain to another domain, for example from Production to Staging, and forget to change the cookie domain.
Note: you can run the provided cookieTest.php
script, which validates what the server cookie domain is, and what is set in the Magento config.
Solution:
Change the Cookie Domain via the Configuration admin menu. Go to System > Configuration > General > Web, as per the screenshot.
Alternatively you can change this by running these SQL queries.
For validating the cookie domain use this select query to get the configuration:
SELECT * FROM core_config_data WHERE path = 'web/cookie/cookie_domain';
After executing this query, we will get the results. Verify the 'value' column is the same as your domain. Update the value if it is not the same as your domain.
To update the cookie domain, use this query:
UPDATE core_config_data SET VALUE = "domain.com" WHERE path = 'web/cookie/cookie_domain';
Reason #2: Multiple subdomains used and Magento’s cookie configuration is incorrect
Let’s say your site is example.com
. Logging into example.com/admin
works fine.
But on your staging/QA site, for example staging.example.com/admin
, you are unable to login without deleting all cookies. The system may allow logins to staging.example.com
, but when we login again to example.com/admin
, your next click on staging.example.com
kicks you back to the login page. Similar behavior is experienced for customers using the front-end login as well.
Solution 1
Option A: If your main domain and subdomains are hosted on the same server
- Change the Cookie Domain via the Configuration admin menu. Go to System > Configuration > General > Web, as per the screenshot.
- See if Cookie Domain is
example.com
, or.example.com
(note the period in front). If not, set it to.example.com
.
Option B: If your main domain and subdomains are hosted on different servers
- Change the Cookie Domain via the Configuration admin menu. Go to System > Configuration > General > Web, as per the screenshot.
- See if the Cookie Domain is
www.example.com
, or.www.example.com
(note the period in front). If not, set it to.www.example.com
. - In the
test.example.com
shop, set the Cookie Domain to.test.example.com
on the test environment.
Alternatively, change this by running these sql queries.
For validating the cookie domain use the following select query to get the configuration:
SELECT * FROM core_config_data WHERE path = 'web/cookie/cookie_domain';
After executing the above query we will get the results. Verify whether the 'value' column is the same as your domain or not. Update the value if it is not same as your domain.
For updating the cookie domain, use the following query:
UPDATE core_config_data SET VALUE = "domain.com" WHERE path = 'web/cookie/cookie_domain';
Solution 2
Check whether your php.ini
file has the same cookie domain as in your Magento config — if not change it to the same as the Magento config, as below:
cookie\_domain = example.com
Solution 3
This is not the recommended approach, but if all options fail you can try this code, changing the option by changing the adminhtml
cookie name for subdomains. Copy the file action.php
and keep it in the same folder path as local so your core code file can be overridden.
There are two changes to make in the file app/code/core/Mage/Core/Controller/Varien/Action.php
.
In the preDispatch
function, change these lines:
/** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $this->_sessionNamespace))->start();
To:
$namespace = $this->_sessionNamespace.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':''); /** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $namespace))->start();
In the function setRedirectWithCookieCheck
, change:
/** @var $session Mage_Core_Model_Session */ session = Mage::getSingleton('core/session', array('name' => $this->_sessionNamespace));
To:
$namespace = $this->_sessionNamespace.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':''); /** @var $session Mage_Core_Model_Session */ $session = Mage::getSingleton('core/session', array('name' => $namespace));
After that, search for the following text in all files:
Mage::getSingleton('core/session', array('name' => 'adminhtml'));`
If any occurrences are found, replace them with:
Mage::getSingleton('core/session', array('name' => 'adminhtml'.($_SERVER['SERVER_NAME']=='subdomain.example.com'?'_subdomain':'')));
Reason #3: Double front-end cookies causing intermittent login issues
In a few scenarios, there is the possibility of the system creating multiple frontend cookies, which prevents the system from allowing you to login..
Scenario 1
When your Magento system has the same configuration for your main domain and subdomain in the Magento config, and if the user logs in to both the sites, Magento creates two cookies. One has 'Domain Value' set with the main domain, and another with the subdomain. As such we will have two front-end cookie sessions, so we won't be able to login to the system.
Solution
Change the Cookie Domain setting to .example.com
for both the domain and subdomain configurations.
Scenario 2
In this scenario, let’s say in your php.ini
, no cookie domain is configured and the Magento Domain Value of example.com
is configured. Now when the user logs in via www.example.com
, the system creates a cookie with a Domain Value of example.com
from the Magento config. When the user logs out, Magento will regenerate the cookie with a Domain Value from the URL accessed (i.e www.example.com
), since in php.ini
no cookie domain was specified. Note that if the user logs in using example.com
or a cookie domain is configured in php.ini
, no issues will arise.
Solution 1
Add a cookie domain to your php.ini
file that is the same as your Magento config.
session.cookie\_domain = example.com
Solution 2
Change the Cookie Domain to .example.com
for both domain and subdomain configurations.
Note: Use our cookieTest.php
script to see if you have double frontend cookies.
Reason #4: Failed to create (read) session ID
Recoverable Error: session\_regenerate\_id(): Failed to create(read) session ID: user (path: /var/lib/php/sessions) in app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 492
This is an error you may see in the exception log, and might occur only for PHP7, as PHP7 does strict type checking.
The solution for this is to change the Magento core read function by typecasting. More on this here.
public function read($sessId) {
//return $data;
return (string)$data;
}
Reason #5: Session data file is not created by your uid
Warning: session_start(): Session data file is not created by your uid in app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 125
Solution 1
This error occurs if you are saving sessions in files, and the folder or files lack webserver user permission. So in the case of nginx, if your webserver user is www-data, you need to grant ownership to the folder using:
sudo chown -R www-data:www-data
Solution 2
If you are running on Vagrant, you may have to make sure or change the file session path.
Solution 3
Another reason is that there could be some old sessions in the var/sessions
folder — delete them and test whether that fixes the problem.
Note: If you have the option to use different session providers, switch to another. For example, go from Redis to file. Clear your var/cache
folder and see if it works — and again, only try this in your development environment.
A PHP Script to Detect Cookie Issues
<?php
ini_set('display_errors', 1);
$mageFileName = getcwd() . '/app/Mage.php';
require $mageFileName;
Mage::app();
echo "<b> Server Cookie Domain Configuration : </b> ".ini_get('session.cookie_domain')."<br>";
foreach (Mage::app()->getStores() as $store) {
echo "<b>" . $store->getName() . "</b><br>";
$configCookieDomain = Mage::getStoreConfig('web/cookie/cookie_domain', $store->getId());
$storeConfigUrl = Mage::getStoreConfig('web/unsecure/base_url', $store->getId());
$sourceUrl = parse_url($storeConfigUrl);
$storeDomain = $sourceUrl['host'];
$cookieDomainResult = ($configCookieDomain == $storeDomain || $configCookieDomain == '.' . $storeDomain) ? "" : "not";
echo "Config cookie Domain : " . $configCookieDomain . " and Store Domain: " . $storeDomain . " " . $cookieDomainResult . " configured properly<br>";
}
//echo "<b>Request Cookies:</b> ";
$requestCookie = Mage::app()->getRequest()->getHeader('cookie');
$requestCookieArr = explode(';', $requestCookie);
$sessionIds = array();
foreach ($requestCookieArr as $requestCookieItem) {
$cookieValue = explode('=', $requestCookieItem);
// echo $requestCookieItem."<br>";
if (trim($cookieValue[0]) == 'frontend' || trim($cookieValue[0]) == 'adminhtml') {
$cookieName = trim($cookieValue[0]);
$sessionId = trim($cookieValue[1]);
$sessionIds[$cookieName][] = $sessionId;
}
}
$areas = array("frontend", "adminhtml");
foreach ($areas as $area => $cookieName) {
echo "<b>validating " . $cookieName . " cookie </b><br>";
$cookieExpires = Mage::getModel('core/cookie')->getLifetime($cookieName);
$cookiePath = Mage::getModel('core/cookie')->getPath($cookieName);
$cookieDomain = Mage::getModel('core/cookie')->getDomain($cookieName);
$cookieSecure = Mage::getModel('core/cookie')->isSecure($cookieName);
$cookieHttpOnly = Mage::getModel('core/cookie')->getHttponly($cookieName);
echo "Cookie Lifetime : " . $cookieExpires . " <br>";
echo "Cookie Path : " . $cookiePath . " <br>";
echo "Cookie Domain : " . $cookieDomain . " <br>";
echo "Cookie Is Secure : " . $cookieSecure . " <br>";
echo "Cookie Httponly : " . $cookieHttpOnly . " <br>";
if (count($sessionIds[$cookieName]) > 1) {
echo "<span style='color:red'><b>We have " . count($sessionIds[$cookieName]) . " " . $cookieName . " Cookies with values : </b>" . implode(',', $sessionIds[$cookieName]) . "<br>";
//$encryptedSessionId = Mage::getSingleton("core/session")->getEncryptedSessionId();
$encryptedSessionId = Mage::getModel('core/cookie')->get($cookieName);
echo "Original Cookie value : " . $encryptedSessionId . "<br>";
echo "Please verify the Subdomain and Main Site Cookie Domain Configuration</span><br>";
}
}
?>
Output:
Magento Store EN
Config cookie Domain : staging.abc.com and Store Domain: staging.abc.com configured properly
Magento Store FR
Config cookie Domain : staging.abc.com and Store Domain: staging.abc.com configured properly
validating frontend cookie
Cookie Lifetime : 31536000
Cookie Path : /
Cookie Domain : staging.zeb.be
Cookie Is Secure :
Cookie Httponly : 1
validating adminhtml cookie
Cookie Lifetime : 31536000
Cookie Path : /
Cookie Domain : staging.zeb.be
Cookie Is Secure :
Cookie Httponly : 1