class RemarkableAuth
Handles the complete authentication flow for reMarkable cloud services, managing device tokens, user tokens, and authenticated HTTP sessions.
/tf/active/vicechatdev/e-ink-llm/cloudtest/auth.py
36 - 112
moderate
Purpose
This class manages the two-stage authentication process required to interact with reMarkable's cloud API. It loads a device token from local files, exchanges it for a user token via the reMarkable API, and maintains an authenticated requests.Session object for subsequent API calls. The class handles token file discovery across multiple locations, provides detailed logging of the authentication process, and manages session headers automatically.
Source Code
class RemarkableAuth:
"""Handles reMarkable authentication flow"""
def __init__(self, config: RemarkableConfig = None):
self.config = config or RemarkableConfig()
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'reMarkable-desktop-win/3.11.1.1951'
})
def load_device_token(self) -> Optional[str]:
"""Load device token from file - checks current directory first, then fallback location"""
# Try current directory first
if self.config.DEVICE_TOKEN_FILE.exists():
token_file = self.config.DEVICE_TOKEN_FILE
elif self.config.FALLBACK_DEVICE_TOKEN_FILE.exists():
token_file = self.config.FALLBACK_DEVICE_TOKEN_FILE
else:
print(f"❌ Device token file not found in:")
print(f" Primary: {self.config.DEVICE_TOKEN_FILE}")
print(f" Fallback: {self.config.FALLBACK_DEVICE_TOKEN_FILE}")
print("💡 You need to create remarkable_device_token.txt with your device token")
return None
try:
with open(token_file, 'r') as f:
token = f.read().strip()
print(f"✅ Loaded device token from {token_file} ({len(token)} chars)")
return token
except Exception as e:
print(f"❌ Error loading device token: {e}")
return None
def get_user_token(self, device_token: str) -> Optional[str]:
"""Get user token using device token"""
headers = {"Authorization": f"Bearer {device_token}"}
try:
print(f"🔑 Requesting user token from: {self.config.USER_TOKEN_URL}")
response = self.session.post(self.config.USER_TOKEN_URL, headers=headers, timeout=30)
if response.status_code == 200:
user_token = response.text.strip()
print(f"✅ User token obtained ({len(user_token)} chars)")
return user_token
else:
print(f"❌ User token request failed: {response.status_code}")
print(f" Response: {response.text}")
return None
except Exception as e:
print(f"❌ User token error: {e}")
return None
def authenticate(self) -> Optional[str]:
"""Complete authentication flow"""
print("🔑 Starting reMarkable authentication...")
device_token = self.load_device_token()
if not device_token:
return None
user_token = self.get_user_token(device_token)
if user_token:
# Update session headers for future API calls
self.session.headers.update({"Authorization": f"Bearer {user_token}"})
print("✅ Authentication complete")
return user_token
return None
def get_authenticated_session(self) -> Optional[requests.Session]:
"""Get an authenticated session ready for API calls"""
user_token = self.authenticate()
if user_token:
return self.session
return None
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
config: Optional RemarkableConfig instance containing configuration settings like token file paths and API URLs. If not provided, a default RemarkableConfig instance is created. This allows customization of file locations and endpoints while providing sensible defaults.
Return Value
Instantiation returns a RemarkableAuth object. Key method returns: load_device_token() returns Optional[str] (device token or None), get_user_token() returns Optional[str] (user token or None), authenticate() returns Optional[str] (user token or None), get_authenticated_session() returns Optional[requests.Session] (authenticated session or None if authentication fails).
Class Interface
Methods
__init__(self, config: RemarkableConfig = None)
Purpose: Initializes the authentication handler with configuration and sets up an HTTP session with appropriate headers
Parameters:
config: Optional RemarkableConfig instance for customizing file paths and API endpoints. Defaults to new RemarkableConfig() if not provided
Returns: None (constructor)
load_device_token(self) -> Optional[str]
Purpose: Loads the device token from a local file, checking the primary location first, then the fallback location
Returns: The device token as a string if found and successfully loaded, None if file not found or error occurs. Prints detailed status messages during execution
get_user_token(self, device_token: str) -> Optional[str]
Purpose: Exchanges a device token for a user token by making an authenticated request to the reMarkable API
Parameters:
device_token: Valid device token string obtained from load_device_token() or stored elsewhere
Returns: User token as a string if the API request succeeds (HTTP 200), None if request fails or encounters an error. Prints detailed status and error messages
authenticate(self) -> Optional[str]
Purpose: Performs the complete authentication flow: loads device token, exchanges it for user token, and updates session headers
Returns: User token as a string if authentication succeeds, None if any step fails. Also updates self.session.headers with the Authorization header for subsequent API calls
get_authenticated_session(self) -> Optional[requests.Session]
Purpose: Convenience method that performs authentication and returns a ready-to-use authenticated session object
Returns: Authenticated requests.Session object if authentication succeeds, None if authentication fails. The returned session has Authorization headers set and is ready for API calls
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
config |
RemarkableConfig | Configuration object containing file paths (DEVICE_TOKEN_FILE, FALLBACK_DEVICE_TOKEN_FILE) and API URLs (USER_TOKEN_URL) used throughout the authentication process | instance |
session |
requests.Session | HTTP session object used for all API requests. Initialized with User-Agent header and updated with Authorization header after successful authentication. Maintains connection pooling and cookies across requests | instance |
Dependencies
requestspathlib
Required Imports
import requests
from pathlib import Path
from typing import Optional
Usage Example
# Basic usage
from remarkable_auth import RemarkableAuth, RemarkableConfig
# Create auth instance with default config
auth = RemarkableAuth()
# Option 1: Get authenticated session directly
session = auth.get_authenticated_session()
if session:
# Use session for API calls
response = session.get('https://api.remarkable.com/some-endpoint')
print(response.json())
# Option 2: Step-by-step authentication
device_token = auth.load_device_token()
if device_token:
user_token = auth.get_user_token(device_token)
if user_token:
# Session is now authenticated
response = auth.session.get('https://api.remarkable.com/some-endpoint')
# Option 3: Just get the user token
user_token = auth.authenticate()
if user_token:
print(f'Authenticated with token: {user_token[:10]}...')
# auth.session is now ready for API calls
# With custom config
custom_config = RemarkableConfig()
auth = RemarkableAuth(config=custom_config)
session = auth.get_authenticated_session()
Best Practices
- Always check return values for None before using tokens or sessions, as authentication can fail at multiple stages
- Use get_authenticated_session() for the simplest workflow - it handles the complete authentication flow
- The session object is reused and maintains state - create one RemarkableAuth instance per application lifecycle
- Device tokens are long-lived but user tokens may expire - consider re-authenticating if API calls start failing
- Store device tokens securely in the remarkable_device_token.txt file with appropriate file permissions
- The class prints detailed status messages to stdout - redirect or capture these if running in a non-interactive environment
- Session headers are automatically updated after successful authentication - no manual header management needed
- Methods can be called independently (load_device_token, get_user_token) or use the convenience methods (authenticate, get_authenticated_session)
- The class checks multiple file locations for the device token (current directory first, then fallback) - place token file in the primary location for best performance
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function create_remarkable_session 80.8% similar
-
function authenticate_remarkable 74.9% similar
-
function test_remarkable_auth 73.9% similar
-
class RemarkableConfig 73.7% similar
-
function test_remarkable_authentication 73.2% similar