Security Best Practices

Security best practices to read before you ship an integration.

Read this before you ship. The API's security model rests on you protecting one thing —
your RSA private key — and handing untrusted clients only short-lived, scoped
access tokens.


The one rule that matters most

Never let your RSA private key leave your backend.

Anyone holding the private key can mint valid tokens for your entire organization. That
means:

  • ❌ Never embed it in browser JavaScript, mobile apps, desktop apps, or any client you
    distribute.
  • ❌ Never commit it to a git repository, paste it into an issue, or log it.
  • ❌ Never send it to Verbatim — only the public key is ever uploaded.
  • ✅ Store it with restrictive permissions (chmod 600) or, better, in a secrets manager
    (Vault, AWS/GCP Secrets Manager, etc.).
  • ✅ Give it the smallest possible blast radius: separate keys per environment
    (staging vs production) and per service.

If a browser or mobile client needs API access, mint an
access token for it instead.


Transport

  • Always use HTTPS. Use the https://…verbatim-ai.com base URLs. Never send a token
    over plain HTTP — it can be captured in transit.
  • Don't put tokens in URLs where you can avoid it (query strings land in server logs, proxy
    logs and browser history). Prefer the Authorization / X-Access-Token headers.

Least privilege

  • Scope every access token to exactly what the client needs and nothing more
    (see scopes). Scope is mandatory for access
    tokens for this reason.
  • For RSA JWTs, remember an empty scope means unrestricted. Reserve unscoped JWTs for
    trusted server-to-server automation; add a scope claim when a narrower token will do.
  • Prefer separate keys/tokens per integration so you can revoke one without disrupting the
    others.

Keep token lifetimes short

  • Access tokens default to 1 hour (ttl = 3600s). Keep them short; mint fresh ones as
    needed rather than issuing long-lived tokens.
  • Sign RSA JWTs with a short exp too (minutes for interactive flows). A leaked token stops
    working when it expires.
  • Provide a lightweight "get me a fresh token" endpoint on your backend for frontends, and
    refresh before expiry.

Rotation & revocation

  • Rotate keys periodically and immediately on any suspected compromise. Because published
    PEM content is write-once, rotation is: generate a new pair → publish it → point your
    signer at the new key id → delete the old key. See
    key lifecycle.
  • Deactivate a key to instantly (and reversibly) stop honoring tokens signed with it;
    delete to retire it permanently.
  • Revoke access tokens on sign-out or suspected leak with
    DELETE /v1/auth/access-token/{token}.
  • Have a written plan for "a key/token leaked": deactivate/revoke first, rotate, then
    investigate.

Handling tokens in the browser

  • Treat any access token as a bearer secret for its (short) lifetime.
  • Avoid persisting tokens in localStorage when you can keep them in memory; if you must
    persist, prefer short TTLs and clear on logout.
  • Scope browser tokens tightly (usually read + query only). A leaked, tightly-scoped,
    short-lived token has limited value.
  • Never expose the backend endpoint that mints tokens without its own authentication —
    otherwise anyone can request tokens for your organization.

CORS & origins

The API responds with permissive CORS so browser clients can call it directly. CORS is not
an authorization boundary
— it controls which sites the browser lets read responses, not
who may call the API. Your real access control is the token and its scope. Don't rely on
origin checks for security; rely on short-lived, scoped tokens.


Checklist

  • Private key stored server-side only, chmod 600 or in a secrets manager.
  • Separate keys per environment (staging / production).
  • Browser/mobile clients use scoped access tokens, never the private key.
  • Access token scopes are minimal.
  • Token lifetimes are short; frontends refresh before expiry.
  • HTTPS everywhere; tokens in headers, not URLs.
  • Documented rotation & revocation procedure.
  • Token-minting endpoint on your backend is itself authenticated.

See also: Authentication · RSA keys ·
Access keys


Did this page help you?