-- web_sessions: browser "passwordless re-login". The opaque cookie token is -- never stored; id holds its SHA-256, so a DB leak yields no usable cookie. -- refresh_token is AES-256-GCM ciphertext (key lives in the container env, not -- the DB). 7-day sliding window: every refresh rotates the token and pushes -- expires_at forward; idle sessions are reaped by DeleteExpiredWebSessions. -- name: CreateWebSession :exec INSERT INTO web_sessions (id, user_id, refresh_token, device_name, user_agent, created_at, last_used_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?); -- name: GetWebSession :one SELECT id, user_id, refresh_token, device_name, user_agent, created_at, last_used_at, expires_at, kind, scope, granted_by, stepped_up_at FROM web_sessions WHERE id = ?; -- SetSessionSteppedUp stamps the moment this session last passed step-up re-auth; -- sensitive actions within the freshness window then skip re-auth (AUTH.md 6). -- name: SetSessionSteppedUp :exec UPDATE web_sessions SET stepped_up_at = ? WHERE id = ?; -- name: RotateWebSession :exec UPDATE web_sessions SET refresh_token = ?, last_used_at = ?, expires_at = ? WHERE id = ?; -- name: SetWebSessionDevice :exec UPDATE web_sessions SET device_name = ? WHERE id = ?; -- name: DeleteWebSession :exec DELETE FROM web_sessions WHERE id = ?; -- name: DeleteExpiredWebSessions :execrows DELETE FROM web_sessions WHERE expires_at < ?; -- CreateSelfSession inserts a cdrop self-signed session (kind self/guest) that has -- no IdP refresh_token (stored empty): refresh mints a fresh access token straight -- from this row without touching the IdP. Used by QR scan-login (AUTH.md 4). -- name: CreateSelfSession :exec INSERT INTO web_sessions (id, user_id, refresh_token, device_name, user_agent, kind, scope, granted_by, created_at, last_used_at, expires_at) VALUES (?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?); -- SlideWebSession pushes a session's sliding window forward without rotating any -- token. Self/guest sessions use it on refresh (they have no refresh_token to -- rotate); oidc sessions keep using RotateWebSession. -- name: SlideWebSession :exec UPDATE web_sessions SET last_used_at = ?, expires_at = ? WHERE id = ?; -- ListWebSessionsByUser lists a user's sessions for the management UI (revoke -- borrowed / guest devices). granted_by ties a scan-approved session to its -- approver for cascade revocation. -- name: ListWebSessionsByUser :many SELECT id, user_id, device_name, user_agent, created_at, last_used_at, expires_at, kind, scope, granted_by FROM web_sessions WHERE user_id = ? ORDER BY last_used_at DESC; -- DeleteWebSessionForUser drops one session scoped to its owner, so a user can -- only revoke their own. -- name: DeleteWebSessionForUser :execrows DELETE FROM web_sessions WHERE id = ? AND user_id = ?;