Security
A scheduler holds the keys to your audience. Here is, concretely, how ScheduleLater holds them. Built to the OWASP ASVS 5.0 Level 2 baseline, self-assessed.
Isolation the database enforces
Every tenant table carries forced row-level security in Postgres, keyed to the workspace. The application connects as a role that cannot bypass it, so a query missing its workspace filter returns nothing rather than someone else’s data. Isolation is a property of the database, not a habit of the code.
- Tenancy
- Workspace-scoped row-level security, forced, fail-closed.
- Runtime role
- Non-superuser, no RLS bypass, data-access grants only.
- Migrations
- Run separately as the owner role; the app cannot alter schema.
Tokens treated like the credentials they are
Platform OAuth tokens and two-factor secrets are envelope-encrypted with AES-256-GCM: a unique key per row, wrapped by a versioned master key that rotates by re-wrapping, never by re-encrypting your data. Tokens never appear in logs, and disconnecting an account revokes the platform grant before deleting the token.
- At rest
- AES-256-GCM envelopes, per-row keys, versioned rotatable master key.
- Passwords
- argon2id with a versioned pepper, checked against known breaches at entry.
- Disconnect
- Revokes the platform grant, deletes the token, purges cached platform data.
Accounts that are hard to take over
Sign-in is email and password with mandatory email verification. TOTP two-factor is available to everyone and required for owners and admins. Sensitive actions, like connecting a platform, minting an API key or disabling two-factor, require fresh re-authentication even inside a valid session.
- Two-factor
- TOTP with single-use recovery codes; required for owner and admin roles.
- Sessions
- 12-hour idle window, 30-day absolute cap, revoke-everywhere on password reset.
- Rate limits
- Per-account and per-address on auth endpoints, failing closed on outage.
Publishing that cannot double-post
A post is claimed for publishing by one atomic database operation; a second worker gets nothing to publish. A crash mid-publish leaves a claim that recovery reclaims safely, and platforms that confirm late are tracked until they answer. Reliability here is a security property: the one thing worse than a missed post is the same post published twice.
- Idempotency
- Database-level atomic claim; YouTube uploads carry a resumable cursor on top.
- Recovery
- Stuck posts, stalled transcodes and unanswered publishes are swept automatically.
- Verification
- A YouTube upload is confirmed accepted after processing, not assumed from a 200.
The perimeter
Every page ships a per-request nonce Content-Security-Policy. Every state-changing request is origin-checked and rate-limited. Server-side fetches of user-supplied URLs resolve and pin addresses to defeat rebinding. Logs are redacted by a single shared policy that knows every secret’s shape. This very site runs the same strict CSP with zero third-party requests.
Questions we did not answer here?
The app’s terms and privacy pages carry the formal commitments.