oqimDocs
API referenceConsole

Start here

  • Introduction
  • Getting started

Guides

  • Telegram accounts
  • Recipients
  • Campaigns
  • Scheduling
  • Webhooks
  • AI writing assistant

AI Seller

  • AI Seller
  • Channels
  • Live inbox
  • Past conversations and privacy
  • Business insights

API

  • Authentication
  • API reference
  • SDK
  • Errors
  • Rate limits

Trust and operations

  • Security
  • Compliance
  • Administration
Docs / Security

Start here

  • Introduction
  • Getting started

Guides

  • Telegram accounts
  • Recipients
  • Campaigns
  • Scheduling
  • Webhooks
  • AI writing assistant

AI Seller

  • AI Seller
  • Channels
  • Live inbox
  • Past conversations and privacy
  • Business insights

API

  • Authentication
  • API reference
  • SDK
  • Errors
  • Rate limits

Trust and operations

  • Security
  • Compliance
  • Administration

Security

Oqim holds Telegram sessions, credentials and personal data for many organizations. This page describes how each is protected, and which parts depend on how you deploy it.

Encryption at rest#

Secrets are stored with envelope encryption. Each value gets its own random 256-bit data key and is encrypted with AES-256-GCM; the data key is then encrypted with a key-encryption key, identified by a key ID stored next to the value. Rotating a key-encryption key means re-wrapping data keys, not re-encrypting every record, and old key IDs keep working while records move over.

Every ciphertext is bound to its tenant and row with additional authenticated data. A Telegram session, for example, is sealed with tg-session:<organization>:<session>, so a ciphertext copied into another organization's row fails to decrypt instead of leaking.

SecretSealed withWho can open it
Telegram sessions (MTProto auth keys)SESSION_KEYWorkers only
Phone numbers during sign-inAPP_KEYAPI and workers; discarded after sign-in
Proxy passwords and MTProto proxy secretsAPP_KEYAPI and workers
Webhook signing secretsAPP_KEYAPI and workers
Two-factor (TOTP) secretsAPP_KEYAPI
  • Session tokens, API keys and invitation tokens are long random values. Oqim stores only their SHA-256 hashes, so a database copy doesn't contain usable credentials.
  • Phone numbers of connected accounts are kept as a keyed hash plus a masked display form, never in the clear. See data minimization.
  • Passwords are hashed with argon2id (19 MiB of memory, 2 iterations, parallelism 1, the OWASP baseline) and a random salt. Sign-in takes the same time whether or not the email exists, so it can't be used to discover accounts.

Key separation#

The API process never holds SESSION_KEY. It forwards sign-in steps and account checks to a worker over an internal HTTP API authenticated with INTERNAL_TOKEN, and only workers decrypt Telegram sessions. Someone who compromises the API process or reads the database still can't use your organization's Telegram accounts.

Protect the keys, not just the database

Keys are 32 random bytes, base64-encoded; oqimctl gen-keys makes them. Keep them in your secret manager, give SESSION_KEY only to workers, and never store them alongside database backups. A backup together with its keys is as sensitive as the live system.

Sign-in and sessions#

  • Console sessions use an HTTP-only, SameSite=Lax cookie that is Secure in production. Page scripts can't read it, and browsers don't attach it to requests other sites make in the background.
  • Anyone can turn on TOTP two-factor authentication. Platform administrators must: the admin console is closed to them until they enroll, and asks for a code in every new session.
  • Disabling a user ends their sessions at once. Revoking an API key ends its access tokens at once.
  • API keys belong to one organization and carry a fixed, limited role. They can't connect accounts, manage people, create other keys or reach the administration API.

Request protection#

  • HTTPS. Run Oqim behind TLS. In production the API sends Strict-Transport-Security for two years, including subdomains.
  • CSRF. A request that changes data with a session cookie must carry an Origin listed in ALLOWED_ORIGINS (or come from the same origin); otherwise it fails with origin_rejected.
  • Headers. Responses carry X-Content-Type-Options: nosniff, X-Frame-Options: DENY and Referrer-Policy: strict-origin-when-cross-origin; API responses are Cache-Control: no-store.
  • Rate limits. Public sign-in endpoints allow 30 requests per minute per IP. See Rate limits.
  • Tenant isolation. The data layer scopes every query to the caller's organization. An ID from another organization returns 404, exactly like one that doesn't exist.
  • Outbound webhooks. In production, webhook URLs must be HTTPS on a public host. Workers check the resolved address at connect time, refuse loopback, private and other reserved ranges, and never follow redirects, so a webhook can't be pointed at internal services.
  • Uploads. Attachments are downloaded with a sandboxing Content-Security-Policy, so an uploaded file can't run scripts in the console's origin.

Audit log#

Security-relevant actions are written to an append-only audit log: sign-ins, two-factor changes, account connections and removals, launches, pauses and cancellations, imports, opt-outs, suppressions, API key and webhook changes, role changes, policy acceptance, and every action by a platform administrator. Each entry records the actor (a user, an API key, the system or a platform administrator), the action, its target, the IP address, the user agent and details.

A database trigger rejects UPDATE, DELETE and TRUNCATE on the audit table, so entries can't be edited or removed through Oqim. Owners and Admins read their organization's log in the console or at GET /audit-logs; platform administrators see every organization's.

What you control#

  • TLS in front of the web and API services, and COOKIE_SECURE left on.
  • ALLOWED_ORIGINS limited to your console and admin hosts.
  • The internal gateway port (8090) reachable only by the API, never from the internet.
  • Where the keys live and who can read them.
  • Two-factor authentication for everyone with the Owner or Admin role, which Oqim offers but doesn't force outside the admin console.
PreviousRate limitsNext Compliance