58 lines
2.4 KiB
Markdown
58 lines
2.4 KiB
Markdown
# Remember-Me Multi-Device Tokens Design (2026-02-28)
|
|
|
|
## Context
|
|
After the security changes on 2026-02-26, remember-me uses a single `users.remember_token` value. This breaks multi-browser usage because each login overwrites the previous token. The goal is to allow unlimited concurrent remember-me sessions across devices and browsers, with retention cleanup for tokens older than 6 months.
|
|
|
|
## Goals
|
|
- Allow unlimited concurrent remember-me sessions per user.
|
|
- Store only hashed tokens in the database.
|
|
- Keep existing cookie security attributes (`Secure`, `HttpOnly`, `SameSite=Lax`).
|
|
- Clean up tokens older than 6 months.
|
|
|
|
## Non-Goals
|
|
- Reworking the entire authentication system.
|
|
- Introducing refresh-token or JWT flows.
|
|
|
|
## Data Model
|
|
Add a new table `users_remember_tokens`:
|
|
- `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
|
|
- `user_id` INT UNSIGNED NOT NULL, indexed
|
|
- `token_hash` CHAR(64) NOT NULL, unique
|
|
- `created_at` DATETIME NOT NULL
|
|
- `last_used_at` DATETIME NULL
|
|
- `user_agent` VARCHAR(255) NULL
|
|
- `ip` VARCHAR(45) NULL
|
|
|
|
Rationale:
|
|
- Store only `token_hash` (SHA-256 of raw token) to avoid storing bearer tokens in plain text.
|
|
- Use `last_used_at` for retention and auditing. If null, fall back to `created_at`.
|
|
|
|
## Login Flow
|
|
1. When user logs in with "Zapamiêtaj mnie":
|
|
- Generate random token (64 hex).
|
|
- Store `hash = sha256(token)` in `users_remember_tokens` with metadata and timestamps.
|
|
- Set cookie to the raw token with expiry +1 year and existing security attributes.
|
|
2. When user logs in without "Zapamiêtaj mnie":
|
|
- Do not create a token.
|
|
- Existing cookie is cleared.
|
|
|
|
## Auto-Login Flow
|
|
1. If no session and cookie exists:
|
|
- Hash cookie value with SHA-256.
|
|
- Look up `users_remember_tokens` by `token_hash`.
|
|
- If found, load user, set session, update `last_used_at`.
|
|
- If not found, clear cookie.
|
|
|
|
## Retention
|
|
- Delete tokens older than 6 months based on `last_used_at` (or `created_at` if `last_used_at` is null).
|
|
- Trigger cleanup during login and auto-login paths to avoid extra jobs.
|
|
|
|
## Error Handling
|
|
- Missing or invalid token in DB results in clearing the cookie and continuing to login screen.
|
|
- No user row for token is treated as invalid and cleaned.
|
|
|
|
## Testing
|
|
- Integration test: login with remember-me sets cookie and inserts token row.
|
|
- Integration test: auto-login succeeds from cookie after session is cleared.
|
|
- Retention test: tokens older than 6 months are removed on login.
|