API Reference
User session management module.
This module provides session management including CRUD operations, device detection, timeout validation, and token rotation for security.
Exports
- CRUD: get_user_sessions, get_session_by_id, get_session_by_id_not_expired, get_session_with_oauth_state, create_session, mark_tokens_exchanged, edit_session, delete_session, delete_idle_sessions, delete_sessions_by_family
- Schemas: UsersSessionsBase, UsersSessionsRead, UsersSessionsInternal
- Models: UsersSessions (ORM model)
- Utils: DeviceType, DeviceInfo, validate_session_timeout, create_session_object, edit_session_object, create_session, edit_session, get_user_agent, get_ip_address, parse_user_agent, cleanup_idle_sessions
DeviceInfo
dataclass
Device information container.
Attributes:
| Name | Type | Description |
|---|---|---|
device_type |
DeviceType
|
Device type (mobile, tablet, PC). |
operating_system |
str
|
OS name. |
operating_system_version |
str
|
OS version string. |
browser |
str
|
Browser name. |
browser_version |
str
|
Browser version string. |
Source code in backend/app/users/users_sessions/utils.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
DeviceType
Bases: Enum
Device type enumeration.
Attributes:
| Name | Type | Description |
|---|---|---|
MOBILE |
Mobile device. |
|
TABLET |
Tablet device. |
|
PC |
Desktop/laptop device. |
Source code in backend/app/users/users_sessions/utils.py
28 29 30 31 32 33 34 35 36 37 38 39 40 | |
UsersSessionsBase
Bases: BaseModel
Base user session schema with safe fields.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
StrictStr
|
Unique session identifier. |
ip_address |
StrictStr
|
Client IP address. |
device_type |
StrictStr
|
Device type. |
operating_system |
StrictStr
|
Operating system name. |
operating_system_version |
StrictStr
|
OS version string. |
browser |
StrictStr
|
Browser name. |
browser_version |
StrictStr
|
Browser version string. |
created_at |
datetime
|
Session creation timestamp. |
last_activity_at |
datetime
|
Last activity timestamp. |
expires_at |
datetime
|
Session expiration timestamp. |
Source code in backend/app/users/users_sessions/schema.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
UsersSessionsInternal
Bases: UsersSessionsBase
Internal user session schema with all fields.
Used for CRUD operations. Includes sensitive fields like refresh_token and csrf_token_hash that should never be exposed in API responses.
Attributes:
| Name | Type | Description |
|---|---|---|
user_id |
StrictInt
|
User ID that owns this session. |
refresh_token |
StrictStr | None
|
Hashed session refresh token. |
oauth_state_id |
StrictStr | None
|
Link to OAuth state for PKCE. |
tokens_exchanged |
StrictBool
|
Prevents duplicate mobile token exchange. |
token_family_id |
StrictStr
|
UUID for token family reuse detection. |
rotation_count |
StrictInt
|
Number of times refresh token rotated. |
last_rotation_at |
datetime | None
|
Timestamp of last token rotation. |
csrf_token_hash |
StrictStr | None
|
Hashed CSRF token for refresh validation. |
Source code in backend/app/users/users_sessions/schema.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
UsersSessionsModel
Bases: Base
User authentication session for tracking active logins.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
Mapped[str]
|
Unique session identifier (UUID). |
user_id |
Mapped[int]
|
Foreign key to users table. |
refresh_token |
Mapped[str]
|
Hashed refresh token for the session. |
ip_address |
Mapped[str]
|
Client IP address. |
device_type |
Mapped[str]
|
Type of device (Mobile, Tablet, PC). |
operating_system |
Mapped[str]
|
Operating system name. |
operating_system_version |
Mapped[str]
|
Operating system version. |
browser |
Mapped[str]
|
Browser name. |
browser_version |
Mapped[str]
|
Browser version. |
created_at |
Mapped[datetime]
|
Session creation timestamp. |
last_activity_at |
Mapped[datetime]
|
Last activity timestamp for idle timeout. |
expires_at |
Mapped[datetime]
|
Session expiration timestamp. |
oauth_state_id |
Mapped[str | None]
|
Link to OAuth state for PKCE validation. |
tokens_exchanged |
Mapped[bool]
|
Prevents duplicate token exchange for mobile. |
token_family_id |
Mapped[str]
|
UUID identifying token family for reuse detection. |
rotation_count |
Mapped[int]
|
Number of times refresh token has been rotated. |
last_rotation_at |
Mapped[datetime | None]
|
Timestamp of last token rotation. |
csrf_token_hash |
Mapped[str | None]
|
Hashed CSRF token for refresh validation. |
users |
Relationship to Users model. |
|
oauth_state |
Relationship to OAuthState model. |
|
rotated_refresh_tokens |
Relationship to RotatedRefreshToken model. |
Source code in backend/app/users/users_sessions/models.py
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | |
UsersSessionsRead
Bases: UsersSessionsBase
User session read schema for API responses.
Extends base with user_id. Excludes sensitive fields like refresh_token and csrf_token_hash.
Source code in backend/app/users/users_sessions/schema.py
51 52 53 54 55 56 57 58 59 | |
cleanup_idle_sessions
cleanup_idle_sessions()
Clean up idle sessions exceeding timeout threshold.
Removes sessions inactive longer than the configured idle timeout period. Only runs if SESSION_IDLE_TIMEOUT_ENABLED. Logs count of cleaned sessions.
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/utils.py
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | |
create_session
create_session(session, db)
Create a new user session in the database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
UsersSessionsInternal
|
The session data to be created. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
UsersSessions
|
The newly created session object. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | |
create_session_object
create_session_object(session_id, user, request, hashed_refresh_token, refresh_token_exp, oauth_state_id=None, csrf_token_hash=None)
Create session object with device and request metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
Unique identifier for the session. |
required |
user
|
UsersRead
|
The user associated with the session. |
required |
request
|
Request
|
HTTP request containing client information. |
required |
hashed_refresh_token
|
str | None
|
Hashed refresh token. |
required |
refresh_token_exp
|
datetime
|
Refresh token expiration datetime. |
required |
oauth_state_id
|
str | None
|
Optional OAuth state ID for PKCE. |
None
|
csrf_token_hash
|
str | None
|
Hashed CSRF token for validation. |
None
|
Returns:
| Type | Description |
|---|---|
UsersSessionsInternal
|
Session object with user, device, and request details. |
Source code in backend/app/users/users_sessions/utils.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |
delete_idle_sessions
delete_idle_sessions(cutoff_time, db)
Delete sessions exceeding the idle timeout threshold.
Removes sessions where last_activity_at is older than the cutoff time. Used by cleanup scheduler to remove inactive sessions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cutoff_time
|
datetime
|
Sessions with last_activity_at before this time will be deleted. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of sessions deleted. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | |
delete_session
delete_session(session_id, user_id, db)
Delete a user session and its associated resources.
Deletes rotated tokens, the session, and any linked OAuth state. Used when user explicitly logs out a session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The unique identifier of the session to delete. |
required |
user_id
|
int
|
The ID of the user associated with the session. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If session not found (404) or database error occurs (500). |
Source code in backend/app/users/users_sessions/crud.py
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | |
delete_sessions_by_family
delete_sessions_by_family(token_family_id, db)
Delete all sessions belonging to a token family.
Used when token reuse is detected to invalidate entire session family as security measure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token_family_id
|
str
|
The family ID to delete sessions for. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of sessions deleted. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | |
edit_session
edit_session(session, db)
Update an existing user session with new field values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
UsersSessionsInternal
|
Session data with fields to update. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If session not found (404) or database error occurs (500). |
Source code in backend/app/users/users_sessions/crud.py
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | |
edit_session_object
edit_session_object(request, hashed_refresh_token, refresh_token_exp, session, csrf_token_hash=None)
Create updated session object with new token and metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
The incoming HTTP request object. |
required |
hashed_refresh_token
|
str
|
Hashed refresh token. |
required |
refresh_token_exp
|
datetime
|
Refresh token expiration datetime. |
required |
session
|
UsersSessionsInternal
|
The existing session object to update. |
required |
csrf_token_hash
|
str | None
|
Hashed CSRF token for validation. |
None
|
Returns:
| Type | Description |
|---|---|
UsersSessionsInternal
|
Updated session object with device and token details. |
Source code in backend/app/users/users_sessions/utils.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
get_ip_address
get_ip_address(request)
Extract client IP address from request.
Checks proxy headers (X-Forwarded-For, X-Real-IP) first, then falls back to direct client host.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
Request object with headers and client info. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Client IP address or "unknown" if indeterminate. |
Source code in backend/app/users/users_sessions/utils.py
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | |
get_session_by_id
get_session_by_id(session_id, db)
Retrieve a user session by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The unique identifier of the session. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
UsersSessions | None
|
The session object if found, None otherwise. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
get_session_by_id_not_expired
get_session_by_id_not_expired(session_id, db)
Retrieve a user session by ID if not expired.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The unique identifier of the session. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
UsersSessions | None
|
The session object if found and not expired, None otherwise. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
get_session_with_oauth_state
get_session_with_oauth_state(session_id, db)
Retrieve a session with its OAuth state for token exchange.
Performs a query to retrieve a session with its linked OAuth state record (if any). Used during mobile token exchange to validate PKCE and ensure the session is valid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The unique identifier of the session. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
tuple[UsersSessions, OAuthState | None] | None
|
Tuple of (session, oauth_state) where oauth_state may be |
tuple[UsersSessions, OAuthState | None] | None
|
None if not linked. Returns None if session not found. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | |
get_user_agent
get_user_agent(request)
Extract User-Agent string from request headers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
The incoming HTTP request object. |
required |
Returns:
| Type | Description |
|---|---|
str
|
User-Agent header value or empty string. |
Source code in backend/app/users/users_sessions/utils.py
301 302 303 304 305 306 307 308 309 310 311 | |
get_user_sessions
get_user_sessions(user_id, db)
Retrieve all sessions for a user, ordered by creation date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
The ID of the user whose sessions to retrieve. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Returns:
| Type | Description |
|---|---|
list[UsersSessions]
|
List of session objects, ordered by most recent first. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If database error occurs. |
Source code in backend/app/users/users_sessions/crud.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
mark_tokens_exchanged
mark_tokens_exchanged(session_id, db)
Mark tokens as exchanged and clear OAuth state.
Sets tokens_exchanged flag to prevent duplicate mobile token exchanges. Deletes the associated OAuth state per OAuth 2.1 best practices (state is ephemeral).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The unique identifier of the session. |
required |
db
|
Session
|
SQLAlchemy database session. |
required |
Raises:
| Type | Description |
|---|---|
HTTPException
|
If session not found (404) or database error occurs (500). |
Source code in backend/app/users/users_sessions/crud.py
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
parse_user_agent
parse_user_agent(user_agent)
Parse user agent string and extract device information.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_agent
|
str
|
The user agent string to parse. |
required |
Returns:
| Type | Description |
|---|---|
DeviceInfo
|
Device information including type, OS, and browser |
DeviceInfo
|
details. Unknown fields default to "Unknown". |
Source code in backend/app/users/users_sessions/utils.py
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | |
validate_session_timeout
validate_session_timeout(session)
Validate session hasn't exceeded idle or absolute timeout.
Only enforces when SESSION_IDLE_TIMEOUT_ENABLED=true. Checks idle timeout (last_activity_at) and absolute timeout (created_at).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
UsersSessions
|
The session to validate. |
required |
Raises:
| Type | Description |
|---|---|
HTTPException
|
401 if session has timed out. |
Source code in backend/app/users/users_sessions/utils.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |