You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug: Remember-me token refresh fails in loginView() - missing ->withCookies() on redirect #1305
Which operating systems have you tested for this bug?
macOS
Which server did you use?
apache
Database
10.11.13-MariaDB
Did you customize Shield?
No
What happened?
[Note : i used Claude Code to redact the text below, bug the issue has been traced by a human]
When a user with a valid remember-me cookie accesses the login page, the loginView() method in LoginController redirects already-logged-in users without preserving cookies.
public function loginView()
{
if (auth()->loggedIn()) {
return redirect()->to(config('Auth')->loginRedirect()); // ❌ Missing ->withCookies()
}
// ...
}
Expected Code:
public function loginView()
{
if (auth()->loggedIn()) {
return redirect()->to(config('Auth')->loginRedirect())->withCookies(); // ✅ Fixed
}
// ...
}
Impact:
When Session::checkRememberMe() validates a remember-me token, it calls refreshRememberMeToken() which:
Generates a new validator
Updates the hashed validator in database
Sends a new cookie via setRememberMeCookie()
However, the redirect at line 34 doesn't include ->withCookies(), so the new cookie is lost. The browser keeps the old cookie with the old validator, which no longer matches the updated hash in the database.
On the next visit, authentication fails with:
hash_equals($token->hashedValidator, $hashedValidator) === false // Session.php:631
Great catch!
Since the redirect() creates a new Response instance, any cookies set in the global response (like the refreshed remember-me token) are indeed dropped unless withCookies() is explicitly called.
Would you be open to submitting a Pull Request for this fix?
Great find—but you're just scratching the surface of the problem. Any CodeIgniter project that uses redirects and Shield is susceptible to the same issue (I've had this problem for two years in my site and couldn't figure it out until you posted your bug report). Rather than requiring every redirect to call withCookies() just in case a new remember me cookie needs to be sent, the better choice is for Shield to automatically add updated remember me cookies to redirect responses. This can be done by Shield replacing CodeIgniter's 'redirectresponse' service. This requires two edits to vendor/codeigniter4/shield/src/Config/Services.php:
Add these additional use statements before the Services class definition:
use Config\Services as AppServices;
use Config\App;
use CodeIgniter\HTTP\RedirectResponse;
Add this additional method to the Services class definition:
public static function redirectresponse(?App $config = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('redirectresponse', $config);
}
$config ??= config(App::class);
$response = new RedirectResponse($config);
$response->setProtocolVersion(AppServices::request()->getProtocolVersion());
// If a remember me cookie is set in the global response, copy it to the redirect response
$rememberCookie = AppServices::response($config)->getCookie(
setting('Auth.sessionConfig')['rememberCookieName']
);
if ($rememberCookie) {
$response->setCookie($rememberCookie);
}
return $response;
}
The above fix automatically adds the new remember me cookie, if present, to all redirect responses. Your proposed fix to Shield's loginView would not be needed.
Thank you for this complement.
Here is a more "generalist" approach with does not limit to "shield" cookies and avoid to edit core files :
1. Create a file app/HTTP/RedirectResponse.php
<?php
namespace App\HTTP;
use CodeIgniter\HTTP\RedirectResponse as BaseRedirectResponse;
class RedirectResponse extends BaseRedirectResponse
{
public function send()
{
// Automatiquement copier les cookies de la Response globale
$this->withCookies();
return parent::send();
}
}
2. Update file app/Config/Services.php
<?php
namespace Config;
use CodeIgniter\Config\BaseService;
use Config\App;
use App\HTTP\RedirectResponse;
/**
* Services Configuration file.
*
* Services are simply other classes/libraries that the system uses
* to do its job. This is used by CodeIgniter to allow the core of the
* framework to be swapped out easily without affecting the usage within
* the rest of your application.
*
* This file holds any application-specific services, or service overrides
* that you might need. An example has been included with the general
* method format you should use for your service methods. For more examples,
* see the core Services file at system/Config/Services.php.
*/
class Services extends BaseService
{
public static function redirectresponse(?App $config = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('redirectresponse', $config);
}
$config ??= config(App::class);
$response = new RedirectResponse($config);
$response->setProtocolVersion(static::request()->getProtocolVersion());
return $response;
}
}
Then, any redirect will automaticly be populated with cookies if needed.
While my code worked, I just noticed that it fills up the log with stack traces, because getCookie() logs whenever the cookie it's looking for isn't found. So instead of calling getCookie() and checking that the result isn't null, call hasCookie() and check that. Here's the revised redirectresponse method:
public static function redirectresponse(?App $config = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('redirectresponse', $config);
}
$config ??= config(App::class);
$response = new RedirectResponse($config);
$response->setProtocolVersion(request()->getProtocolVersion());
// If a remember me cookie is set in the global response, copy it to the redirect response
$cookieName = setting('Auth.sessionConfig')['rememberCookieName'];
if (static::response($config)->hasCookie($cookieName)) {
$response->setCookie(static::response($config)->getCookie($cookieName));
}
return $response;
}
Activity
datamweb commentedon Jan 8, 2026
Great catch!
Since the
redirect()creates a newResponseinstance, any cookies set in the global response (like the refreshedremember-metoken) are indeed dropped unlesswithCookies()is explicitly called.Would you be open to submitting a Pull Request for this fix?
Bug: Remember-me token refresh fails in loginView() - missing ->withC…
tomatlscomm commentedon Jan 8, 2026
Done
LenoilR commentedon Jan 26, 2026
Great find—but you're just scratching the surface of the problem. Any CodeIgniter project that uses redirects and Shield is susceptible to the same issue (I've had this problem for two years in my site and couldn't figure it out until you posted your bug report). Rather than requiring every redirect to call withCookies() just in case a new remember me cookie needs to be sent, the better choice is for Shield to automatically add updated remember me cookies to redirect responses. This can be done by Shield replacing CodeIgniter's 'redirectresponse' service. This requires two edits to vendor/codeigniter4/shield/src/Config/Services.php:
The above fix automatically adds the new remember me cookie, if present, to all redirect responses. Your proposed fix to Shield's loginView would not be needed.
tomatlscomm commentedon Jan 26, 2026
Hi.
Thank you for this complement.
Here is a more "generalist" approach with does not limit to "shield" cookies and avoid to edit core files :
1. Create a file app/HTTP/RedirectResponse.php
2. Update file app/Config/Services.php
Then, any redirect will automaticly be populated with cookies if needed.
LenoilR commentedon Feb 6, 2026
While my code worked, I just noticed that it fills up the log with stack traces, because getCookie() logs whenever the cookie it's looking for isn't found. So instead of calling getCookie() and checking that the result isn't null, call hasCookie() and check that. Here's the revised redirectresponse method:
Bug: Remember-me token refresh fails in loginView() - missing ->withC…
fix: Remember-me token refresh fails in loginView() - missing withCoo…