Add Token Restoration Support for Session Persistence#29
Conversation
- Add stored_tokens parameter to NavienAuthClient for restoring saved tokens - Add AuthTokens.to_dict() for serializing tokens with issued_at timestamp - Enhance AuthTokens.from_dict() to support both API and stored data formats - Skip authentication when valid stored tokens provided - Auto-refresh expired JWT tokens or re-authenticate if AWS creds expired - Add 7 new tests covering token serialization and restoration flows - Add examples/token_restoration_example.py demonstrating workflow - Update authentication documentation with token restoration guide Benefits: - Reduces API load and improves startup time - Prevents rate limiting for frequently restarting applications - Enables session persistence across application restarts
- Replace manual token reconstruction with stored_tokens parameter - Use AuthTokens.to_dict() and from_dict() for serialization - Simplify token storage code by leveraging built-in methods - Remove unnecessary manual validation logic - Properly manage context manager lifecycle for auth client Benefits: - Cleaner, more maintainable code - Automatic token refresh and AWS credential re-authentication - Consistent with new token restoration pattern
There was a problem hiding this comment.
Pull Request Overview
This PR adds token restoration support to enable session persistence across application restarts, reducing API load and preventing rate limiting for frequently restarting applications.
Key Changes
- Added
stored_tokensparameter toNavienAuthClientfor restoring previously saved sessions - Implemented
AuthTokens.to_dict()and enhancedfrom_dict()for token serialization/deserialization - Modified
NavienAuthClient.__aenter__()to intelligently handle stored tokens with automatic refresh/re-authentication
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/nwp500/auth.py |
Implements core token restoration logic with serialization methods and smart authentication handling |
tests/test_auth.py |
Adds 7 comprehensive tests covering token serialization, restoration, and expiration scenarios |
src/nwp500/cli/token_storage.py |
Refactors CLI token storage to use new built-in serialization methods |
src/nwp500/cli/__main__.py |
Updates CLI authentication flow to leverage stored tokens parameter |
examples/token_restoration_example.py |
Provides complete example demonstrating token save/restore workflow |
docs/python_api/auth_client.rst |
Documents token restoration feature with examples |
CHANGELOG.rst |
Documents the new feature for version 4.8.0 |
src/nwp500/cli/__main__.py
Outdated
| auth_client = NavienAuthClient(email, password, stored_tokens=tokens) | ||
|
|
||
| # Enter the context manager to authenticate/restore session | ||
| await auth_client.__aenter__() |
There was a problem hiding this comment.
Manually calling __aenter__() breaks the context manager pattern and can lead to resource leaks if an exception occurs before __aexit__() is called. Use the context manager properly with async with instead of manual enter/exit calls. If you need the client outside the context manager scope, refactor to use async with and return the client for use within that scope.
src/nwp500/cli/__main__.py
Outdated
| # Auth client close will close the underlying aiohttp session | ||
| await auth_client.close() | ||
| # Also call __aexit__ to properly clean up context manager | ||
| await auth_client.__aexit__(None, None, None) |
There was a problem hiding this comment.
Manually calling __aexit__() is error-prone and violates the context manager pattern. If __aenter__() was never called or failed, this will cause issues. Use async with to ensure proper resource management, or use a try/finally block with the manual calls to guarantee cleanup.
- Replace 'or' operator with explicit None/empty string checks - Add helper function get_value() to correctly check both camelCase and snake_case - Prevent empty strings in camelCase keys from blocking snake_case fallback - Add test for empty string and None value handling This fixes the issue where empty strings would be treated as truthy, preventing the fallback to snake_case alternatives.
- Replace manual __aenter__/__aexit__ calls with async with context manager - Eliminate error-prone manual context manager lifecycle management - Move authentication logic directly into async_main() - Remove now-unused get_authenticated_client() helper function - Remove unused Optional import Benefits: - Guaranteed proper cleanup even on exceptions - More Pythonic and follows best practices - Simpler control flow with single entry point - Eliminates potential resource leaks from failed __aenter__ calls
Overview
This PR adds token restoration support to enable session persistence across application restarts. This reduces API load, improves startup time, and prevents rate limiting for frequently restarting applications (e.g., Home Assistant integrations).
Changes
Core Features
stored_tokensparameter toNavienAuthClient.__init__()for restoring previously saved tokensAuthTokens.to_dict()method for serializing tokens (includesissued_attimestamp)AuthTokens.from_dict()to support both API responses (camelCase) and stored data (snake_case)NavienAuthClient.__aenter__()to skip authentication when valid stored tokens are providedTesting
Documentation & Examples
examples/token_restoration_example.pydemonstrating complete save/restore workflowdocs/python_api/auth_client.rstwith token restoration guideBenefits
Testing Performed
Breaking Changes
None - this is a backward-compatible addition. Existing code continues to work without modifications.
Related Issues
Addresses session persistence requirements for long-running applications and Home Assistant integrations.