Skip to content

Token Management

JWT Configuration

Token Expiry Rotation
access_token 15 minutes No
refresh_token 7 days On every use

Token Payload

{
  "sub": "user-uuid",
  "tenant_id": "tenant-uuid",
  "role": "admin",
  "exp": 1704067200
}

Token Storage (Backend)

Sessions stored in database with hashed refresh token:

class SessionModel(SQLModel, table=True):
    id: UUID = Field(primary_key=True)
    user_id: UUID = Field(foreign_key="users.id")
    refresh_token_hash: str = Field(max_length=255)
    expires_at: datetime
    created_at: datetime

Token Storage (Frontend)

Tokens encrypted with Fernet/AES before storing in SharedPreferences:

# core/security/encryption.py
from cryptography.fernet import Fernet

class TokenEncryption:
    def __init__(self, key: bytes):
        self._fernet = Fernet(key)

    def encrypt(self, token: str) -> str:
        return self._fernet.encrypt(token.encode()).decode()

    def decrypt(self, encrypted: str) -> str:
        return self._fernet.decrypt(encrypted.encode()).decode()

Automatic Token Refresh

Frontend TokenManager handles automatic refresh:

# core/security/token_manager.py
class TokenManager:
    def should_refresh_token(self) -> bool:
        # Refresh 2 minutes before expiry
        expires_at = self._get_token_expiry()
        return (expires_at - datetime.now()).total_seconds() < REFRESH_BEFORE_EXPIRY_MINUTES * 60

Environment Variables

# Session & Token Security
SESSION_TIMEOUT_MINUTES=15
REFRESH_BEFORE_EXPIRY_MINUTES=2
ENCRYPT_TOKENS=true

# Optional encryption
TOKEN_ENCRYPTION_KEY=your-256bit-key
MACHINE_ID=unique-machine-id
APP_SECRET=your-app-secret

Security Measures

  1. Token Encryption: Fernet/AES for tokens in SharedPreferences
  2. HTTPS Enforcement: Block HTTP requests in production
  3. Session Timeout: 15 minutes default (SESSION_TIMEOUT_MINUTES)
  4. Automatic Refresh: Refresh 2 minutes before expiry
  5. Refresh Token Rotation: New refresh token on every use

Session Storage Keys

# Keys stored in SharedPreferences
ACCESS_TOKEN_KEY = "access_token"
REFRESH_TOKEN_KEY = "refresh_token"
USER_DATA_KEY = "user_data"
SESSION_TIMESTAMP_KEY = "session_timestamp"
THEME_PREFERENCE_KEY = "theme_preference"
LANGUAGE_PREFERENCE_KEY = "language_preference"