CoolCMS API

LoginDeviceCookie
in package

FinalYes

The "known device" proof for the password-login throttle: a long-lived signed cookie that says "this browser has signed in to account X before".

Why: the per-account counter across all IPs (ratelimit.loginAccount) let anyone who knows a user name lock the owner out of password login. When that counter is over its limit, a request carrying a valid device cookie of the same account still gets its password verified; one without it is refused unverified (AuthPresenter::internalActionLogin()).

Stateless — no table: v1.<deviceId>.<userId>.<expiresTs>.<hmac>. The HMAC key is derived from the shared app secret (%jwt.secret%) with a purpose label, so the cookie signature can never be confused with a JWT or another HMAC of the same secret (AccountDeletionTicket, EditorAutosaveScope). The device id is random (128 bits) and has its own failure counter (ratelimit.loginDevice), so a stolen cookie is not a licence for unlimited guessing.

Front and Admin issue the cookie after a successful password or OAuth sign-in and pass its raw value into the Api login call, where it is verified here — the Api trusts the signature, never a flag from the caller.

Table of Contents

Constants

COOKIE_NAME  : string = 'cms_login_device'
KEY_PURPOSE  : string = 'cms:login-device-cookie:v1'
VERSION  : string = 'v1'

Properties

$key  : string
$rateLimitConfig  : RateLimitConfig

Methods

__construct()  : mixed
getLifetimeSeconds()  : int
issue()  : string
New cookie value for `$userId`. A still valid cookie of the same account keeps its device id (the expiry moves on), so the device failure counter follows the browser, not the sign-in.
parse()  : array{deviceId: string, userId: int}|null
Signature and expiry only — the account binding is checked by the caller.
verify()  : string|null
Device id of a valid cookie issued for `$userId`, or null (malformed, forged, expired, another account).
sign()  : string

Constants

Properties

Methods

issue()

New cookie value for `$userId`. A still valid cookie of the same account keeps its device id (the expiry moves on), so the device failure counter follows the browser, not the sign-in.

public issue(int $userId, string|null $currentToken, int $now) : string
Parameters
$userId : int
$currentToken : string|null
$now : int
Return values
string

parse()

Signature and expiry only — the account binding is checked by the caller.

public parse(string $token, int $now) : array{deviceId: string, userId: int}|null
Parameters
$token : string
$now : int
Return values
array{deviceId: string, userId: int}|null

verify()

Device id of a valid cookie issued for `$userId`, or null (malformed, forged, expired, another account).

public verify(string $token, int $userId, int $now) : string|null
Parameters
$token : string
$userId : int
$now : int
Return values
string|null

sign()

private sign(string $deviceId, int $userId, int $expires) : string
Parameters
$deviceId : string
$userId : int
$expires : int
Return values
string
On this page

Search results