Stale sessions from a stolen device could be reused up to the cache
TTL after a legitimate user re-logs in, because login never cleared
the existing cache entry.
Changes:
- Add invalidate_by_user(user_id) to SessionCache protocol
- InMemorySessionCache maintains a user_id -> set[token] index to
support O(1) invalidation of all sessions for a given user
- NoOpSessionCache stub updated for API compatibility
- auth_service.login() now returns the Session object alongside
signed_token and expires_at
- login router calls session_cache.invalidate_by_user(session.id)
immediately after successful authentication
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>