Authentication¶
The otf-api library authenticates against OrangeTheory's AWS Cognito backend. All token management, refresh, and device registration is handled automatically.
Credential Setup¶
There are three ways to provide credentials, checked in this order:
1. Direct credentials¶
Pass your email and password directly when creating the client:
from otf_api import Otf
from otf_api.auth import OtfUser
user = OtfUser(username="you@example.com", password="your-password")
otf = Otf(user=user)
2. Environment variables¶
Set OTF_EMAIL and OTF_PASSWORD in your environment:
export OTF_EMAIL="you@example.com"
export OTF_PASSWORD="your-password"
Then create the client without arguments:
from otf_api import Otf
otf = Otf() # reads from environment
3. Interactive prompt¶
If no credentials are found and the session is interactive (TTY attached), the library prompts for your email and password at runtime. This is useful for quick scripts and notebooks.
from otf_api import Otf
otf = Otf() # prompts if env vars are missing
Warning
The interactive prompt requires a TTY. In non-interactive environments (CI, cron jobs, Docker containers), you must use environment variables or direct credentials.
How Auth Works¶
When you create an Otf client, the library:
- Checks the disk cache for valid tokens from a previous session
- If cached tokens exist and are not expired, uses them directly
- If no valid cache exists, authenticates with Cognito using the SRP (Secure Remote Password) protocol
- Stores the resulting tokens in the disk cache for future sessions
All of this happens transparently — you never need to manage tokens yourself.
Token Caching¶
Tokens are persisted to disk using diskcache, stored in a platform-appropriate cache directory with a version prefix based on the library's major version (e.g., ~/.cache/otf-api/v0/ for the current 0.x series). This means:
- Subsequent script runs reuse existing tokens without re-authenticating
- Tokens automatically expire from the cache when they become invalid
- The cache is versioned by major library version to avoid conflicts during upgrades
Clearing the cache¶
If you encounter auth issues, clear the cache:
from otf_api.cache import clear_cache
clear_cache()
This removes both token and device data, forcing a fresh login on next use.
Device Key Management¶
The Cognito user pool used by OrangeTheory requires device confirmation. On first authentication, the library:
- Receives a device key from Cognito as part of the auth response
- Confirms the device using a cryptographic verifier
- Caches the device key, group key, and password for future sessions
The device key is required for token refresh to work. Without it, refresh attempts fail with NOT_AUTHORIZED.
Note
The library confirms devices but does not "remember" them (no MFA bypass). This matches the behavior of the official OTF mobile app.
Token Refresh¶
Access tokens have a limited lifetime (typically 1 hour). The library handles refresh automatically:
- Before each API request, the token expiration is checked
- If the access token has expired, it is silently refreshed using the stored refresh token and device key
- If the refresh token itself has expired, the cache is cleared and a
NoCredentialsErroris raised
You do not need to handle refresh logic in your code.
The OtfUser Class¶
OtfUser is the primary authentication object. It wraps the Cognito interaction and exposes:
| Attribute | Description |
|---|---|
cognito_id |
The Cognito subject ID (sub claim) |
member_uuid |
The OTF member UUID (used in API calls) |
email_address |
The authenticated user's email |
httpx_auth |
The HTTPX auth handler attached to API requests |
You can pass an OtfUser instance to Otf() or let the client create one internally.
Troubleshooting¶
Wrong credentials
If you see NotAuthorizedException or UserNotFoundException, double-check your email and password. The email is case-sensitive.
Stale cache
If authentication worked previously but now fails with token errors, clear the cache:
from otf_api.cache import clear_cache
clear_cache()
Non-interactive environments
If you see NoCredentialsError: Unable to prompt for credentials in a non-interactive shell, ensure OTF_EMAIL and OTF_PASSWORD environment variables are set.