Skip to content

Security

Secret management, authentication, and encryption for production applications.

Overview

The security module provides:

  • Secret Management: Secure storage and retrieval from multiple backends
  • Authentication: Token providers and rotation
  • Encryption: Symmetric encryption and password hashing
  • Best Practices: Production-ready security patterns

Secret Management

Why Secret Management?

Secrets (API keys, passwords, tokens) should never be: - Hardcoded in source code - Committed to version control - Logged in plain text - Shared between environments

Secret Backends

Environment Variables

Simple, works everywhere:

from dspu.security import SecretManager

# Load from environment
secrets = SecretManager.from_env()
api_key = await secrets.get("API_KEY")

Use Case: Development, simple deployments, containers

HashiCorp Vault

Enterprise secret management:

# Connect to Vault
secrets = SecretManager.from_vault(
    url="https://vault.example.com",
    token="s.abc123"
)

# Read secret
db_password = await secrets.get("database/password")

Use Case: Enterprise, multi-environment, secret rotation

AWS Secrets Manager

AWS-native secret storage:

# Connect to AWS Secrets Manager
secrets = SecretManager.from_aws(region="us-east-1")

# Read secret
api_key = await secrets.get("prod/api/key")

Use Case: AWS deployments, IAM integration

Auto-Detection

Automatically select backend:

# Tries Vault → AWS → Environment
secrets = SecretManager.from_env()

Secret Operations

# Get secret
value = await secrets.get("key")

# Set secret (if backend supports)
await secrets.set("key", "value")

# List secrets
keys = await secrets.list_secrets("prefix/*")

Authentication

Authentication Providers

Static Token

Simple API key authentication:

from dspu.security import StaticTokenProvider

auth = StaticTokenProvider(token="sk_live_abc123")
token = await auth.get_token()

# Use in requests
headers = {"Authorization": f"Bearer {token}"}

JWT

JSON Web Tokens:

from dspu.security import JWTProvider

auth = JWTProvider(
    secret_key="your-secret-key",
    issuer="my-service",
    expiry_seconds=3600  # 1 hour
)

# Generate token
token = await auth.get_token(
    scopes=["read", "write"],
    claims={"user_id": 123}
)

# Verify token
claims = auth.verify_token(token)

OAuth2

OAuth2 client credentials flow:

from dspu.security import OAuth2Provider

auth = OAuth2Provider(
    client_id="client_id",
    client_secret="client_secret",
    token_url="https://auth.example.com/token"
)

token = await auth.get_token()

Token Rotation

Automatic token refresh:

from dspu.security import RotatingToken, TokenData

# Define refresh function
async def fetch_token() -> TokenData:
    response = await auth_api.get_token()
    return TokenData(
        token=response["access_token"],
        expires_at=parse_expiry(response["expires_in"])
    )

# Create rotating token
async with RotatingToken(
    fetch_fn=fetch_token,
    refresh_before=300  # Refresh 5 minutes before expiry
) as rotating:
    # Always get fresh token
    headers = {"Authorization": f"Bearer {rotating.current}"}
    await api_client.get("/data", headers=headers)

Benefits: - Automatic refresh before expiry - Thread-safe access - Callbacks for monitoring

Encryption

Fernet (Simple)

Symmetric encryption:

from dspu.security import Fernet

# Generate key
key = Fernet.generate_key()
cipher = Fernet(key)

# Encrypt
encrypted = cipher.encrypt(b"sensitive data")

# Decrypt
decrypted = cipher.decrypt(encrypted)

Use Case: Simple encryption, config files, database fields

AES-256-GCM (Advanced)

Authenticated encryption:

from dspu.security import AES

# Generate key
key = AES.generate_key()
cipher = AES(key)

# Encrypt
encrypted = cipher.encrypt(b"sensitive data")

# Decrypt (verifies authenticity)
decrypted = cipher.decrypt(encrypted)

Use Case: High-security requirements, authenticated data

Password Hashing

Never store plain text passwords:

from dspu.security import hash_password, verify_password

# Hash password before storing
hashed = hash_password("user_password")
user.password_hash = hashed

# Verify on login
if verify_password("user_password", user.password_hash):
    # Login successful
    ...

Features: - PBKDF2 with SHA-256 - Automatic salt generation - Configurable iterations

Secure Tokens

Generate cryptographically secure tokens:

from dspu.security import generate_secure_token

# Generate random token
token = generate_secure_token(length=32)  # 32 bytes = 64 hex chars

# Use for session IDs, API keys, etc.

Data Hashing

Integrity verification:

from dspu.security import hash_data

# Hash data
hash_value = hash_data(b"data", algorithm="sha256")

# Compare hashes (constant time)
from dspu.security import constant_time_compare

is_same = constant_time_compare(hash1, hash2)

Common Patterns

Pattern 1: Application Configuration

from dspu.security import SecretManager
from dspu.config import Config, FileSource, EnvSource

# Load base config from file
config = Config.load_from_file(AppConfig, "config.yaml")

# Load secrets separately
secrets = SecretManager.from_env()
config.database.password = await secrets.get("database/password")
config.api_key = await secrets.get("api/key")

Pattern 2: Service Authentication

from dspu.security import JWTProvider, RotatingToken

# Setup JWT provider
jwt_secret = await secrets.get("jwt/secret")
auth = JWTProvider(secret_key=jwt_secret, expiry_seconds=900)

# Create rotating token
async def fetch_token():
    token = await auth.get_token(scopes=["api:read", "api:write"])
    # Token expires in 900 seconds
    expires_at = datetime.now() + timedelta(seconds=900)
    return TokenData(token=token, expires_at=expires_at)

async with RotatingToken(fetch_fn=fetch_token) as rotating:
    # Use rotating.current in all API calls
    await api.call(token=rotating.current)

Pattern 3: Database Field Encryption

from dspu.security import Fernet

# Get encryption key from secrets
encryption_key = await secrets.get("encryption/key")
cipher = Fernet(encryption_key.encode())

# Encrypt before storing
class User:
    def __init__(self, email: str, phone: str):
        self.email_encrypted = cipher.encrypt(email.encode())
        self.phone_encrypted = cipher.encrypt(phone.encode())

    @property
    def email(self) -> str:
        return cipher.decrypt(self.email_encrypted).decode()

    @property
    def phone(self) -> str:
        return cipher.decrypt(self.phone_encrypted).decode()

Pattern 4: API Key Generation

from dspu.security import generate_secure_token, hash_password

# Generate API key
api_key = f"sk_live_{generate_secure_token(32)}"

# Hash before storing (like passwords)
api_key_hash = hash_password(api_key)
store_in_database(user_id, api_key_hash)

# Verify on API request
if verify_password(provided_key, stored_hash):
    # Valid API key
    ...

Best Practices

Secret Management

DO: - Use Vault or cloud secret managers in production - Rotate secrets regularly - Use environment variables for simple deployments - Separate secrets by environment - Audit secret access

DON'T: - Don't commit secrets to git - Don't log secrets - Don't hardcode secrets - Don't share secrets between environments - Don't use weak secrets

Authentication

DO: - Use short-lived tokens (15-60 minutes) - Implement automatic token rotation - Store JWT secrets in secret manager - Use HTTPS for all token transmission - Validate tokens on every request

DON'T: - Don't use weak signing keys - Don't skip token expiry checks - Don't store tokens in localStorage (XSS risk) - Don't share tokens between services - Don't log tokens

Encryption

DO: - Use AES-256-GCM for authenticated encryption - Generate keys with cryptographically secure methods - Store keys separately from encrypted data - Implement key rotation - Use Fernet for simplicity

DON'T: - Don't roll your own cryptography - Don't use weak algorithms (DES, RC4, MD5) - Don't hardcode encryption keys - Don't skip authentication (use GCM/HMAC) - Don't reuse keys across environments

Password Security

DO: - Always hash passwords before storing - Use PBKDF2/bcrypt/scrypt/Argon2 - Generate random salts per password - Use sufficient iterations (100,000+) - Enforce strong password requirements

DON'T: - Don't store plain text passwords - Don't use simple hashing (MD5, SHA1) - Don't use same salt for all passwords - Don't skip salts - Don't allow weak passwords

Security Checklist

Development

  • No secrets in source code
  • No secrets in version control
  • .gitignore configured for secrets
  • Local secrets in environment/files
  • Secrets documented

Production

  • Secrets in secret manager (Vault/AWS)
  • TLS/HTTPS everywhere
  • Token rotation implemented
  • Encryption keys rotated
  • Audit logging enabled
  • Secrets access restricted (IAM/RBAC)
  • Regular security reviews

Code

  • Input validation
  • Output encoding
  • SQL injection prevention
  • XSS prevention
  • CSRF protection
  • Rate limiting
  • Authentication on all endpoints
  • Authorization checks

Installation

# With security extras
pip install 'dspu[security]'

Includes: - cryptography - Encryption - pyjwt - JWT tokens - hvac - Vault integration

Next Steps