Skip to content

Security: GetYourFit/beta

Security

docs/Security.md

GYF Security

Security measures implemented in the GYF backend.

Authentication

Feature Implementation File
JWT tokens HS256 with configurable expiry (default: 7 days) services/auth_service.py
Password hashing bcrypt via passlib services/auth_service.py
Token extraction Bearer token from Authorization header dependencies.py
Secret validation Rejects default secret in non-dev environments config.py

JWT Secret

The JWT secret must be set via environment variable in staging/production:

export GYF_ENV=production
export JWT_SECRET=$(openssl rand -base64 32)

The app will refuse to start if GYF_ENV != dev and the default secret is used.

Rate Limiting

Setting Default Configuration
Requests/minute 60 RATE_LIMIT_PER_MINUTE env var
Key function Client IP address slowapi
Response 429 Too Many Requests Automatic
Storage In-memory (use Redis URL for distributed) rate_limit.py

Security Headers

API responses (backend middleware)

All API responses include OWASP-recommended headers:

Header Value
X-Content-Type-Options nosniff
X-Frame-Options DENY
X-XSS-Protection 1; mode=block
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy camera=(), microphone=(), geolocation=()
Strict-Transport-Security max-age=31536000; includeSubDomains (HTTPS only)

Document responses (nginx)

CSP is set on the HTML document response via nginx, not on API responses (where it has no security effect and causes browser console warnings):

Directive Value
default-src 'self'
script-src 'self' 'unsafe-inline' 'unsafe-eval'
style-src 'self' 'unsafe-inline'
img-src 'self' data: blob: https:
connect-src 'self' ws: wss:
font-src 'self' https://fonts.gstatic.com

Role-Based Access Control (RBAC) & Multi-Tenancy

JWT tokens include a role claim (default: user).

# Protect an endpoint:
from backend.app.dependencies import require_role

@router.post("/admin-action", dependencies=[Depends(require_role("admin"))])
async def admin_action(): ...

# Available roles: "user", "admin", "b2b_partner" (extensible)

B2B Multi-Tenancy

The system supports full data isolation for B2B clients via the TenantContextMiddleware.

  • Identity Resolution: Resolves tenant contexts either via X-API-KEY (B2B requests) or X-Tenant-ID / Auth Token (D2C/Internal requests).
  • Data Isolation: SQLAlchemy queries use apply_tenant_filter to implicitly scope WHERE tenant_id = X.
  • API Keys: Managed via /admin/api-keys, keys are securely verified with SHA-256 caching.

Middleware Stack Order

SecurityHeadersMiddleware  (outermost — runs last on response)
    ↓
CORSMiddleware
    ↓
RateLimiter
    ↓
PrometheusMiddleware
    ↓
RequestLoggingMiddleware  (innermost — runs first on request)

Test Coverage

Test What it verifies
test_security_headers_present All OWASP headers on every response
test_security_headers_no_hsts_on_http HSTS only on HTTPS
test_rbac_unauthorized_no_token 401 without auth token
test_jwt_decode_full Role claim in JWT
test_jwt_decode_full_default_role Default role is "user"

There aren't any published security advisories