Security and data handling
How Topicary stores, protects, and serves your documentation.
Hosting
Topicary runs on Vercel's global edge network. All traffic is served over HTTPS with automatic TLS (Transport Layer Security) certificate provisioning and renewal. Vercel provides built-in DDoS (distributed denial of service) protection and automatic scaling.
Database
Content is stored in Supabase-managed PostgreSQL. Databases are encrypted at rest using AES-256. Supabase provides automated daily backups with point-in-time recovery.
Content is stored as TipTap/ProseMirror JSON, a structured document format that preserves formatting, hierarchy, and metadata without relying on raw HTML.
Access control
Every database table uses PostgreSQL Row-Level Security (RLS). Users can only read and write data for projects they belong to. There are no shared tables or global read access to project data. Even direct database queries are scoped to the authenticated user's project membership.
Three roles control what project members can do:
Role | Permissions |
|---|---|
Admin | Full access including project settings, member management, billing, and all content operations |
Author | Create, edit, and publish content; manage topics, maps, and components |
Reviewer | Read-only access through review sessions (no Topicary account required) |
Authentication
User accounts use Supabase Auth with email and password. Sessions are refreshed on every request through server-side middleware. Dashboard routes are protected, so unauthenticated requests redirect to the login page. Password reset is available from the login page through an emailed reset link.
Enterprise accounts can additionally sign in through Set up SSO (SAML 2.0).
Published-site sessions
Published sites that use password protection issue their own session, separate from your dashboard login. These sessions are HMAC-SHA256 signed and expire after 24 hours. Changing a site's password immediately invalidates existing reader sessions.
Published sites
Published documentation sites are publicly accessible by design, so anyone with the URL can read them. Do not publish sensitive internal documentation unless you intend it to be publicly available.
Published content is served using a read-only database connection dedicated to serving published content. This client bypasses RLS because published sites are intended for anonymous readers, not project members.
Review access
Reviewers access content through a unique token link, with no Topicary account required. Each review session generates its own token. Tokens grant read-only access to the topics included in that review session.
Content sanitization
All content rendered on published sites is sanitized before serving:
Category | Allowed | Blocked |
|---|---|---|
Event handlers | None |
|
URI protocols |
|
|
Data URIs |
|
|
Custom CSS | Standard CSS properties |
|
Example of how sanitization transforms content:
<!-- Before sanitization (authored content) -->
<a href="javascript:alert('xss')">Click here</a>
<img src="photo.jpg" onerror="alert('xss')" />
<div style="background: url('https://evil.com/track')">Content</div>
<!-- After sanitization (published output) -->
<a>Click here</a>
<img src="photo.jpg" />
<div>Content</div>API key security
REST API authentication are never stored in plaintext. Each key is `tk_`-prefixed. When a key is generated, Topicary returns the full key to the user once and stores only a SHA-256 hash. Subsequent authentication checks hash the incoming Bearer token and compare it against the stored hash. This means:
A database breach does not expose usable API keys.
Lost keys cannot be recovered. They must be revoked and regenerated.
Each key is scoped to a single project and has an optional expiration date.
Webhook security
Configure webhooks deliveries are signed using HMAC-SHA256. Each webhook subscription has its own signing secret. Topicary computes the HMAC of the request body using the secret and includes it in the `X-Topicary-Signature` header. Recipients should verify this signature using a timing-safe comparison to prevent forged requests.
Webhook signing secrets can be rotated at any time from Settings > Webhooks. After rotation, the old secret is immediately invalid.
SSO / SAML security
Set up SSO (SAML 2.0) responses are verified using the identity provider's X.509 certificate. Topicary validates:
The XML signature on the SAML assertion matches the configured certificate.
The
NotBeforeandNotOnOrAfterconditions are within the current time window.The
Audiencerestriction matches the Topicary entity ID.
SAML assertions are processed server-side only, so no assertion data is exposed to the browser.
Encryption
GitHub sync tokens (used for the Sync with GitHub feature) are encrypted at rest using AES-256-GCM before storage. Integration credentials (Zendesk, Salesforce, Phrase TMS) are stored in the integration_configs table with the same encryption approach.
Data storage and versioning
Topics are auto-versioned on every save. When content changes, a snapshot is stored in a separate versions table. Identical consecutive saves are deduplicated.
Map versions duplicate the map structure (item order and nesting) while sharing the same underlying topics.
Deleting and exporting your data
You can delete a whole project from Settings > Danger zone by typing the project name to confirm. This permanently removes the project and its content.
Content export is per map or per topic. Publish a map to a web or PDF target, or use the export options to download content as Markdown (and, on the Enterprise tier, DITA, Word, OKF, or XLIFF).
There is no self-serve button to delete your entire account or download all account data at once. To close your account or request a full data export, contact support and the Topicary team will process the request.
Product analytics
Topicary collects anonymized product usage analytics by default to improve the app. Capture is anonymized and does not set advertising cookies, so no cookie-consent banner is shown. This is separate from the reader analytics collected on your published sites, which cover reader search, page feedback, and AI queries.
Security summary
Layer | Protection |
|---|---|
Transport | HTTPS with automatic TLS (Vercel) |
Infrastructure | DDoS protection, automatic scaling (Vercel) |
Database | AES-256 encryption at rest, daily backups with PITR (Supabase) |
Access control | PostgreSQL RLS on every table |
Authentication | Supabase Auth, server-side session refresh; SAML 2.0 SSO (Business) |
API keys | SHA-256 hashed at rest, project-scoped, optional expiration |
Webhooks | HMAC-SHA256 signed deliveries, per-subscription secrets |
Secrets | AES-256-GCM encryption for GitHub tokens and integration credentials |
Content output | HTML sanitization (event handlers, URI protocols, data URIs, CSS) |
See also
Sync with GitHub: GitHub sync tokens are encrypted using AES-256-GCM as described above
REST API authentication: API key generation, scoping, and revocation
Configure webhooks: HMAC-SHA256 signature verification for webhook deliveries
Set up SSO (SAML 2.0): X.509 certificate verification and SAML assertion validation
Create a review session: how review tokens grant scoped read-only access without requiring accounts
Plans and limits: plan tiers that determine available features and access control scope
Publish a web site: published sites are publicly accessible; understand the security implications