From f71a8ba184d26771011fb9b89d3232a2e2433e5b Mon Sep 17 00:00:00 2001 From: klsoft-web Date: Sun, 13 Sep 2026 10:20:48 +0300 Subject: [PATCH 1/3] Add the 'cookieSecure' parameter to enable 'CookieLogin' to set a cookie when an HTTP request is made --- CHANGELOG.md | 1 + README.md | 2 ++ config/params.php | 1 + src/Login/Cookie/CookieLogin.php | 6 ++++-- tests/Login/Cookie/CookieLoginTest.php | 16 ++++++++++++++++ 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 986f8c5..0a793e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Enh #127: Bump `yiisoft/auth` version to `^3.3.0`, and fix deprecated classes usage (@klsoft-web, @vjik) - Enh #132: Bump `yiisoft/session` version to `^3.0.2` (@vjik) - New #126: Add optional HMAC signing of the auto-login cookie value via `CookieLogin` signature key (@vjik) +- Bug #135: Add the `cookieSecure` parameter to enable `CookieLogin` to set a cookie when an HTTP request is made (@klsoft-web) ## 2.3.2 December 23, 2025 diff --git a/README.md b/README.md index fec4ac5..4934920 100644 --- a/README.md +++ b/README.md @@ -349,12 +349,14 @@ return [ 'cookieLogin' => [ 'forceAddCookie' => true, 'duration' => 'P5D', // 5 days + 'cookieSecure' => true, // whether the client should send back the cookie only over HTTPS connection ], ], ]; ``` > If you want the cookie to be a session cookie, change the duration to `null`. +> To enable a cookie to be set when an HTTP request is made, change the `cookieSecure` to `false`. #### Removing a cookie diff --git a/config/params.php b/config/params.php index 8d8b9c9..ed3a682 100644 --- a/config/params.php +++ b/config/params.php @@ -9,6 +9,7 @@ 'forceAddCookie' => false, 'duration' => 'P5D', // 5 days, see format on https://www.php.net/manual/dateinterval.construct.php 'signatureKey' => null, // secret key to sign the auto-login cookie value; keep `null` to store it unsigned + 'cookieSecure' => true, // whether the client should send back the cookie only over HTTPS connection ], ], ]; diff --git a/src/Login/Cookie/CookieLogin.php b/src/Login/Cookie/CookieLogin.php index 87abc55..edd7296 100644 --- a/src/Login/Cookie/CookieLogin.php +++ b/src/Login/Cookie/CookieLogin.php @@ -50,10 +50,12 @@ final class CookieLogin * the auto-login cookie is session cookie that expires when browser is closed. * @param string|null $signatureKey Secret key used to sign the auto-login cookie value with HMAC-SHA256. If it * isn't set, the cookie value is stored without a signature and isn't protected against tampering. + * @param bool $cookieSecure Whether the client should send back the cookie only over HTTPS connection. */ public function __construct( private readonly ?DateInterval $duration = null, private readonly ?string $signatureKey = null, + private readonly bool $cookieSecure = true, ) {} /** @@ -93,7 +95,7 @@ public function addCookie( $cookieValue = $this->createValue((string) $identity->getId(), $identity->getCookieLoginKey(), $expires); - return (new Cookie(name: $this->cookieName, value: $cookieValue, expires: $expires)) + return (new Cookie(name: $this->cookieName, value: $cookieValue, expires: $expires, secure: $this->cookieSecure)) ->addToResponse($response); } @@ -106,7 +108,7 @@ public function addCookie( */ public function expireCookie(ResponseInterface $response): ResponseInterface { - return (new Cookie($this->cookieName)) + return (new Cookie($this->cookieName, secure: $this->cookieSecure)) ->expire() ->addToResponse($response); } diff --git a/tests/Login/Cookie/CookieLoginTest.php b/tests/Login/Cookie/CookieLoginTest.php index abc5c86..38e4b63 100644 --- a/tests/Login/Cookie/CookieLoginTest.php +++ b/tests/Login/Cookie/CookieLoginTest.php @@ -238,6 +238,22 @@ public function testParseValueInvalidUnsigned(string $value): void $this->assertNull($cookieLogin->parseValue($value)); } + public function testAddCookieWithDisableCookieSecure(): void + { + $cookieLogin = new CookieLogin(cookieSecure: false); + + $identity = new CookieLoginIdentity(); + + $response = new Response(); + $response = $cookieLogin->addCookie($identity, $response); + + $this->assertMatchesRegularExpression( + '#autoLogin=%5B%2242%22%2C%22auto-login-key-correct%22%2C0%5D;' + . ' Path=/; HttpOnly; SameSite=Lax#', + $response->getHeaderLine('Set-Cookie'), + ); + } + private function extractCookieValue(string $setCookieHeader): string { $pair = explode(';', $setCookieHeader, 2)[0]; From 7dc83facbaf52aca5dad049dabcae4ac6d42b995 Mon Sep 17 00:00:00 2001 From: klsoft-web Date: Wed, 16 Sep 2026 09:17:36 +0300 Subject: [PATCH 2/3] Refactoring --- CHANGELOG.md | 2 +- README.md | 4 ++-- config/di-web.php | 1 + config/params.php | 2 +- src/Login/Cookie/CookieLogin.php | 8 ++++---- tests/ConfigTest.php | 3 +++ tests/Login/Cookie/CookieLoginTest.php | 4 ++-- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a793e4..8d06642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Enh #127: Bump `yiisoft/auth` version to `^3.3.0`, and fix deprecated classes usage (@klsoft-web, @vjik) - Enh #132: Bump `yiisoft/session` version to `^3.0.2` (@vjik) - New #126: Add optional HMAC signing of the auto-login cookie value via `CookieLogin` signature key (@vjik) -- Bug #135: Add the `cookieSecure` parameter to enable `CookieLogin` to set a cookie when an HTTP request is made (@klsoft-web) +- Bug #135: Add the `secureCookie` parameter to enable `CookieLogin` to set a cookie when an HTTP request is made (@klsoft-web) ## 2.3.2 December 23, 2025 diff --git a/README.md b/README.md index 4934920..8d0fcd2 100644 --- a/README.md +++ b/README.md @@ -349,14 +349,14 @@ return [ 'cookieLogin' => [ 'forceAddCookie' => true, 'duration' => 'P5D', // 5 days - 'cookieSecure' => true, // whether the client should send back the cookie only over HTTPS connection + 'secureCookie' => true, // whether the client should send back the cookie only over HTTPS connection ], ], ]; ``` > If you want the cookie to be a session cookie, change the duration to `null`. -> To enable a cookie to be set when an HTTP request is made, change the `cookieSecure` to `false`. +> To enable a cookie to be set when an HTTP request is made, change the `secureCookie` to `false`. #### Removing a cookie diff --git a/config/di-web.php b/config/di-web.php index 2b666f8..f7659ef 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -44,6 +44,7 @@ new DateInterval($params['yiisoft/user']['cookieLogin']['duration']) : null, 'signatureKey' => $params['yiisoft/user']['cookieLogin']['signatureKey'], + 'secureCookie' => $params['yiisoft/user']['cookieLogin']['secureCookie'], ], ], ]; diff --git a/config/params.php b/config/params.php index ed3a682..03c658c 100644 --- a/config/params.php +++ b/config/params.php @@ -9,7 +9,7 @@ 'forceAddCookie' => false, 'duration' => 'P5D', // 5 days, see format on https://www.php.net/manual/dateinterval.construct.php 'signatureKey' => null, // secret key to sign the auto-login cookie value; keep `null` to store it unsigned - 'cookieSecure' => true, // whether the client should send back the cookie only over HTTPS connection + 'secureCookie' => true, // whether the client should send back the cookie only over HTTPS connection ], ], ]; diff --git a/src/Login/Cookie/CookieLogin.php b/src/Login/Cookie/CookieLogin.php index edd7296..4a27590 100644 --- a/src/Login/Cookie/CookieLogin.php +++ b/src/Login/Cookie/CookieLogin.php @@ -50,12 +50,12 @@ final class CookieLogin * the auto-login cookie is session cookie that expires when browser is closed. * @param string|null $signatureKey Secret key used to sign the auto-login cookie value with HMAC-SHA256. If it * isn't set, the cookie value is stored without a signature and isn't protected against tampering. - * @param bool $cookieSecure Whether the client should send back the cookie only over HTTPS connection. + * @param bool $secureCookie Whether the client should send back the cookie only over HTTPS connection. */ public function __construct( private readonly ?DateInterval $duration = null, private readonly ?string $signatureKey = null, - private readonly bool $cookieSecure = true, + private readonly bool $secureCookie = true, ) {} /** @@ -95,7 +95,7 @@ public function addCookie( $cookieValue = $this->createValue((string) $identity->getId(), $identity->getCookieLoginKey(), $expires); - return (new Cookie(name: $this->cookieName, value: $cookieValue, expires: $expires, secure: $this->cookieSecure)) + return (new Cookie(name: $this->cookieName, value: $cookieValue, expires: $expires, secure: $this->secureCookie)) ->addToResponse($response); } @@ -108,7 +108,7 @@ public function addCookie( */ public function expireCookie(ResponseInterface $response): ResponseInterface { - return (new Cookie($this->cookieName, secure: $this->cookieSecure)) + return (new Cookie($this->cookieName, secure: $this->secureCookie)) ->expire() ->addToResponse($response); } diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 5f926ff..17c3ca5 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -52,6 +52,7 @@ public function testBase(): void ->getInaccessibleProperty($cookieLogin, 'duration') ->d); $this->assertNull($this->getInaccessibleProperty($cookieLogin, 'signatureKey')); + $this->assertTrue($this->getInaccessibleProperty($cookieLogin, 'secureCookie')); $cookieLoginMiddleware = $container->get(CookieLoginMiddleware::class); @@ -68,6 +69,7 @@ public function testOverrideParams(): void 'forceAddCookie' => true, 'duration' => 'P2D', 'signatureKey' => 'test-signature-key', + 'secureCookie' => false ], ], ]); @@ -86,6 +88,7 @@ public function testOverrideParams(): void ->getInaccessibleProperty($cookieLogin, 'duration') ->d); $this->assertSame('test-signature-key', $this->getInaccessibleProperty($cookieLogin, 'signatureKey')); + $this->assertFalse($this->getInaccessibleProperty($cookieLogin, 'secureCookie')); $cookieLoginMiddleware = $container->get(CookieLoginMiddleware::class); diff --git a/tests/Login/Cookie/CookieLoginTest.php b/tests/Login/Cookie/CookieLoginTest.php index 38e4b63..6bb6c09 100644 --- a/tests/Login/Cookie/CookieLoginTest.php +++ b/tests/Login/Cookie/CookieLoginTest.php @@ -238,9 +238,9 @@ public function testParseValueInvalidUnsigned(string $value): void $this->assertNull($cookieLogin->parseValue($value)); } - public function testAddCookieWithDisableCookieSecure(): void + public function testAddCookieWithDisableSecureCookie(): void { - $cookieLogin = new CookieLogin(cookieSecure: false); + $cookieLogin = new CookieLogin(secureCookie: false); $identity = new CookieLoginIdentity(); From 11550226726a57804d05530f0ffcc8d5ca931fe7 Mon Sep 17 00:00:00 2001 From: klsoft-web Date: Fri, 18 Sep 2026 07:46:51 +0300 Subject: [PATCH 3/3] A warning about the possible consequences of deactivating secureCookie has been included --- CHANGELOG.md | 2 +- README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d06642..bd55e62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Enh #127: Bump `yiisoft/auth` version to `^3.3.0`, and fix deprecated classes usage (@klsoft-web, @vjik) - Enh #132: Bump `yiisoft/session` version to `^3.0.2` (@vjik) - New #126: Add optional HMAC signing of the auto-login cookie value via `CookieLogin` signature key (@vjik) -- Bug #135: Add the `secureCookie` parameter to enable `CookieLogin` to set a cookie when an HTTP request is made (@klsoft-web) +- Enh #135: Add the `secureCookie` parameter to enable `CookieLogin` to set a cookie when an HTTP request is made (@klsoft-web) ## 2.3.2 December 23, 2025 diff --git a/README.md b/README.md index 8d0fcd2..cdcb6f9 100644 --- a/README.md +++ b/README.md @@ -358,6 +358,9 @@ return [ > If you want the cookie to be a session cookie, change the duration to `null`. > To enable a cookie to be set when an HTTP request is made, change the `secureCookie` to `false`. +> [!warning] +> With secureCookie turned off, it travels in cleartext and can be captured and replayed for the full duration of cookie lifetime (5 days by default). + #### Removing a cookie The `Yiisoft\User\Login\Cookie\CookieLoginMiddleware` automatically removes the cookie after the logout.