Fix/session and device management#67
Merged
Merged
Conversation
…ssion_for_auth signature
Collaborator
Author
|
Before these changes:
After these changes:
Architecture: how we track session recencyOptions considered
Throttle mechanics
Eviction logicif existing_session is None:
sessions: list[UserSession] = []
async for s in self.session_querier.list_sessions_by_user(user_id=user_id):
sessions.append(s)
if len(sessions) >= AuthService.SESSION_LIMIT:
oldest = min(sessions, key=lambda s: (s.last_active, s.created_at))
await SessionService.delete_session_cache(redis, oldest.id)
await self.session_querier.delete_session_by_id(id=oldest.id, user_id=user_id)
logger.warning("session_evicted user_id=%s evicted_session_id=%s", user_id, oldest.id)
Test reactivationThe old
Files changed
TestingUnit tests
Integration tests (real Postgres)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR: Phase 1 & 2 — Schema Migration + Core Service Layer Rewrite
What this PR does
Implements the first two phases of the Session & Device Management rebuild. The original bug was: device ownership was exclusive (one device row = one user globally), causing reassignment conflicts when the same physical device logged in as a different user. This PR fixes the ownership model and cleans up the device/session lookup path.
Phase 1 — Schema migration
user_devices.physical_device_id— new UUID column, NOT NULL, with unique index(user_id, physical_device_id). Device ownership is now a composite key: the same physical device can legitimately belong to multiple users.user_devices.id— kept as surrogate PK.user_sessions.device_idFK still points here; no cascade migration needed.refresh_tokenstable — new table withsession_id(FK, cascade delete),family_id,token_hash(unique),used,used_at. Populated in Phase 3.GetDeviceByPhysicalId(scoped),GetAnyDeviceByPhysicalId(unscoped,:many). UpdatedCreateDeviceto includephysical_device_id.sqlc generate— regenerated from updated schema.Phase 2 — Core service layer rewrite
_ensure_device_for_login— completely rewritten:(user_id, physical_device_id)instead of unscopedget_device_by_id_any_create_mobile_session— was usingreq.device_id(physical ID) directly asuser_sessions.device_id(surrogate PK). Now correctly captures the returneddevice.idfrom_ensure_device_for_login.get_session_by_device_for_userfirst; cap only applies to genuinely new sessions.MobileAuthBaseRequest.device_id→physical_device_id— makes the API contract unambiguous. Surrogatedevice_idis only used server-side (revoke, token update, inactivate, session list).create_deviceinDeviceService— had its own hardcoded 3-device cap and was missingphysical_device_id; confirmed unused via grep.Design decisions
UNIQUE(user_id, device_id)on sessions + mobile-only app = no legitimate multi-session-per-device case; self-heals orphaned sessionsINSERT ... ON CONFLICT ... DO UPDATE)idstays stableTesting
MULTAI_RUN_E2E=1and running server + workers)Checklist
sqlc generateproduces clean outputruff check .cleanmypyclean