# Affiliate Platform Security

**Last Updated:** 2026-02-24

Security scope and requirements for the Ordio Loop affiliate partner platform (HubSpot integration, partner auth, session/cookies, partner data, cron).

## Scope

- **HubSpot API token**: Loaded from environment; no fallback in production.
- **Partner authentication**: Session-based login with password hashing (bcrypt), lockout, secure cookie params.
- **Partner data**: Stored in JSON files under `v2/data/` or `writable/`; blocked from direct web access.
- **Cron**: Sync script runs CLI-only; not executable via web.

## Production Requirements

1. **HubSpot API token**
   - Set `HUBSPOT_API_TOKEN` in the environment. In production (ordio.com or `ORDIO_ENV=production`), the app will not use a fallback and will exit with an error if the token is missing.
   - Never commit real tokens to version control.

2. **HTTPS**
   - Serve the partner area over HTTPS so session and remember-me cookies use the `Secure` flag.

3. **Session and cookies**
   - Session cookie: `HttpOnly`, `Secure` (when HTTPS), `SameSite=Lax`; strict mode and cookies-only (no URL session ID).
   - Remember-me cookie: same attributes via options array.
   - Configured in `v2/includes/affiliate-auth.php` before `session_start()`.

4. **Remember-me token storage**
   - Tokens stored in `affiliate_remember_tokens.json` (same path tier as `affiliate_partners.json`).
   - Selector:validator pattern: cookie contains `selector:validator`; only SHA-256 hash of validator stored.
   - Validation uses `hash_equals()` for constant-time comparison (timing-attack resistant).
   - Tokens invalidated on logout and on password change.
   - Test script: `php v2/scripts/affiliate/test-remember-me.php`.

5. **CORS**
   - Partner login, register, and password-reset APIs allow only allowlisted origins: `https://www.ordio.com`, `https://ordio.com`; in non-production, `http://localhost` and `http://127.0.0.1` (and port 8003) are allowed. No wildcard `*`.

6. **File access**
   - `.htaccess` denies direct web access to `v2/data/*.json` and `writable/*.json` (403).
   - Sensitive affiliate JSON files (`affiliate_partners.json`, `affiliate_remember_tokens.json`) are listed in `.gitignore` so they are not committed.

7. **Cron**
   - `v2/cron/sync-affiliate-hubspot.php` checks `php_sapi_name() === 'cli'` and returns 403 when run via web.

## OAuth Social Login

- **Credentials:** `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` loaded from environment via `oauth-config.php`. Never commit to version control.
- **State validation:** OAuth callback validates CSRF `state` token (stored in session, compared with `hash_equals`).
- **Account linking:** Only auto-link when OAuth provider attests email is verified (`email_verified`). Never link on unverified email (account takeover risk).
- **Error notifications:** OAuth failures (token exchange, userinfo) logged; critical errors sent to hady@ordio.com.

## Optional Improvements

- **Rate limiting**: Limit partner-register and partner-reset-password (request action) by IP (e.g. max requests per hour per IP) to reduce abuse and enumeration. Use a simple file-based or existing rate-limit mechanism; document here when added.
- **CSRF**: Partner change-password (and optionally login/register) can be protected with CSRF tokens. With CORS restricted to same-origin and `SameSite=Lax` cookies, cross-site POSTs from other origins are already limited; add explicit CSRF if you need stronger guarantees.

## References

- [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md) – Pre-launch and deployment steps, including security.
- [CRON_SYNC_RUNBOOK.md](CRON_SYNC_RUNBOOK.md) – Sync cron schedule, lockfile, and troubleshooting.
