\begin{article}
LaTeX API Authentication Best Practices
Secure your LaTeX compilation API integration — manage API keys safely, rotate credentials, and avoid common authentication mistakes.

Every FormatEx integration starts with an API key. That key is a bearer credential — whoever holds it can compile documents against your account, consume your monthly quota, and in the wrong hands, rack up overages or expose your pipeline to abuse. Getting LaTeX API authentication right from day one costs almost nothing; cleaning up after a leaked key does not.
This guide covers the full lifecycle: creating scoped keys, storing them safely, rotating them without downtime, detecting leaks early, and integrating with secrets managers for production deployments.
How FormatEx API Key Authentication Works
FormatEx uses a simple, stateless scheme. Every request to the compile endpoint must include your API key in the X-API-Key header:
curl -X POST https://api.formatex.io/api/v1/compile \
-H "X-API-Key: fex_live_ӢӢӢӢӢӢӢӢӢӢӢӢӢӢӢӢ" \
-H "Content-Type: application/json" \
-d '{
"latex": "\\documentclass{article}\\begin{document}Hello\\end{document}",
"engine": "pdflatex"
}' \
--output document.pdfUnder the hood, FormatEx stores a SHA-256 hash of your key — the raw value is shown only once at creation time and never stored in plaintext. If you lose it, you create a new one. There is no "view key" button.
The key prefix (fex_live_) lets you identify production keys at a glance in logs or incident reports, without exposing the secret portion. Remember this — it matters when you set up automated leak detection.
Creating and Scoping API Keys
The FormatEx dashboard lets you create multiple keys per account (limit depends on your plan: 2 on Free, up to 50 on Scale). Use this to scope keys by environment and purpose rather than sharing one key everywhere.
Recommended key topology:
| Key name | Environment | Used by |
|---|---|---|
ci-pdflatex | CI/CD pipeline | GitHub Actions, test suite |
staging-api | Staging server | Your staging backend |
prod-api | Production | Your production backend |
local-dev | Developer laptops | Individual devs (rotate frequently) |
Never share a production key with a CI pipeline. If your CI config is ever exposed (and they are — misconfigured public repos happen), your production quota and any soft-block plans are immediately at risk. Separate keys mean a compromised CI key affects only CI.
When you create a key in the dashboard (Dashboard → API Keys → New Key), copy it immediately into your secrets store. Do not paste it into Slack, a notes app, or a terminal with scrollback logging.
Storing API Keys Safely
The single most common mistake is hardcoding a key directly in source code:
// NEVER do this
const client = new FormatExClient({
apiKey: "fex_live_abc123xyz789...",
});That string will end up in your git history forever, visible to anyone with repo access — including future contributors, contractors, and anyone who ever gets read access to the repo. Deleting the line in a follow-up commit does not remove it from history.
The correct approach: environment variables.
// src/lib/formatex.ts
const API_KEY = process.env.FORMATEX_API_KEY;
if (!API_KEY) {
throw new Error("FORMATEX_API_KEY environment variable is not set");
}
export async function compileLaTeX(latex: string, engine = "pdflatex") {
const response = await fetch("https://api.formatex.io/api/v1/compile", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ latex, engine }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Compilation failed: ${error.error}`);
}
return response.arrayBuffer();
}For local development, use a .env.local file (never committed) with a dedicated local key. Add .env* to your .gitignore before you write the first line:
# .env.local
FORMATEX_API_KEY=fex_live_your_local_dev_key_here# .gitignore
.env
.env.local
.env*.localIn Python projects, the same pattern applies via python-dotenv or your framework's built-in env loading:
import os
import httpx
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["FORMATEX_API_KEY"] # Raises KeyError if missing — good
def compile_latex(latex: str, engine: str = "pdflatex") -> bytes:
response = httpx.post(
"https://api.formatex.io/api/v1/compile",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={"latex": latex, "engine": engine},
timeout=120.0,
)
response.raise_for_status()
return response.contentNote the explicit raise_for_status() — never silently swallow HTTP errors from an authentication-gated API.
Rotating Keys Without Downtime
Keys should be rotated periodically — quarterly at minimum, immediately after any suspected exposure. The zero-downtime rotation procedure for FormatEx is straightforward because you can hold multiple active keys simultaneously:
- Create a new key in the dashboard with the same name convention (e.g.,
prod-api-2026-q3). - Deploy your application with the new key value in your secrets store — the old key is still active, so in-flight requests complete normally.
- Verify the new key is working by checking compilation logs in the dashboard.
- Revoke the old key from the dashboard once traffic has fully shifted.
For automated rotation with AWS Secrets Manager, you can script steps 1 and 4 via the FormatEx dashboard API (when available) or handle them manually on a calendar reminder. The key point is that revocation happens after the new key is live, not before.
# Example: update the key in an existing AWS Secrets Manager secret
aws secretsmanager put-secret-value \
--secret-id prod/formatex/api-key \
--secret-string '{"FORMATEX_API_KEY":"fex_live_new_key_here"}'Your application should read the secret at startup (or refresh it periodically), not bake it into a container image or deployment artifact.
Using Secrets Managers in Production
For production deployments, environment variables in a .env file are not enough. A secrets manager provides audit logs, access control, versioning, and automatic rotation hooks. Here are the three most common options:
AWS Secrets Manager
import boto3
import json
def get_formatex_key() -> str:
client = boto3.client("secretsmanager", region_name="us-east-1")
secret = client.get_secret_value(SecretId="prod/formatex/api-key")
return json.loads(secret["SecretString"])["FORMATEX_API_KEY"]HashiCorp Vault
# Store the key
vault kv put secret/formatex/prod api_key=fex_live_...
# Retrieve at deploy time
export FORMATEX_API_KEY=$(vault kv get -field=api_key secret/formatex/prod)GitHub Actions (for CI pipelines)
Store the key as a repository or organization secret in GitHub (Settings → Secrets and variables → Actions), then reference it in your LaTeX compilation workflow in CI/CD:
- name: Compile LaTeX documents
env:
FORMATEX_API_KEY: ${{ secrets.FORMATEX_API_KEY_CI }}
run: |
curl -X POST https://api.formatex.io/api/v1/compile \
-H "X-API-Key: $FORMATEX_API_KEY" \
-H "Content-Type: application/json" \
-d @payload.json \
--output output.pdfGitHub Actions secrets are masked in logs — if you accidentally echo $FORMATEX_API_KEY, GitHub replaces it with ***. This is a useful safety net but not a substitute for not logging keys in the first place.
Detecting and Responding to Leaked Keys
Leaked API keys are more common than most teams expect. A single accidental git push of a .env file, a Slack paste, or a verbose error log can expose a credential. You need a detection strategy, not just a prevention strategy. Understanding how FormatEx sandboxes and secures the compilation environment also helps you reason about the full attack surface.
Set up automated scanning:
- GitHub secret scanning — free for public repos, available on GitHub Advanced Security for private repos. Add a custom pattern for
fex_live_[A-Za-z0-9]{20,}to catch FormatEx keys specifically. - truffleHog — scans git history, not just the current HEAD. Run it as a pre-push hook or in CI.
- gitleaks — another git-history scanner with a broad default ruleset.
# Run truffleHog against your repo before pushing
trufflehog git file://. --only-verified
# Or as a pre-push git hook
echo 'trufflehog git file://. --only-verified' >> .git/hooks/pre-push
chmod +x .git/hooks/pre-pushWhen a key is confirmed leaked, act immediately:
- Revoke the key in the FormatEx dashboard right now — do not wait.
- Check your compilation logs (Dashboard → Usage) for unexpected usage in the past 24—72 hours.
- Rotate all keys in the same environment (assume lateral exposure).
- Find and remove the leaked credential from all locations (git history via
git filter-repo, Slack message deletion, log scrubbing). - Conduct a brief post-mortem to close the gap that allowed the leak.
Revoking a key in the dashboard takes effect immediately — any subsequent request using that key returns a 401.
Authentication Error Handling
Robust integrations handle auth errors explicitly rather than crashing or silently failing. For a complete reference of every status code the API can return, see the LaTeX API error codes guide:
type CompileError = {
error: string;
};
async function compilePDF(latex: string): Promise<ArrayBuffer> {
const response = await fetch("https://api.formatex.io/api/v1/compile", {
method: "POST",
headers: {
"X-API-Key": process.env.FORMATEX_API_KEY ?? "",
"Content-Type": "application/json",
},
body: JSON.stringify({ latex, engine: "pdflatex" }),
});
if (response.status === 401) {
// Key is missing, invalid, or revoked
throw new Error(
"FormatEx authentication failed. Check FORMATEX_API_KEY in your environment."
);
}
if (response.status === 403) {
// Key is valid but plan limit exceeded or engine not allowed
const body: CompileError = await response.json();
throw new Error(`FormatEx authorization error: ${body.error}`);
}
if (!response.ok) {
const body: CompileError = await response.json();
throw new Error(`Compilation failed (${response.status}): ${body.error}`);
}
return response.arrayBuffer();
}A 401 means your key is wrong or missing. A 403 means your key is valid but your plan does not permit the requested operation — for example, using the xelatex engine on a Free plan (which only supports pdflatex). These are distinct failure modes that warrant different handling. For production resilience beyond auth errors, pair this with exponential backoff and retry logic for rate limit responses.
Summary
Getting LaTeX API authentication right comes down to a handful of habits applied consistently:
- One key per environment — never reuse a production key in CI or development
- Environment variables only — no hardcoded keys, ever, anywhere in source
- Secrets managers for production — AWS Secrets Manager, Vault, or equivalent
- Automated leak detection — truffleHog or gitleaks in CI, GitHub secret scanning enabled
- Quarterly rotation as a calendar event — do not wait for an incident
- Immediate revocation on any suspected leak — the dashboard revokes in seconds
FormatEx is designed to support this workflow: multiple concurrent keys, instant revocation, and key prefixes that make it easy to identify credential type in logs. The infrastructure is there — use it.
Ready to build a secure LaTeX compilation pipeline? Sign up for FormatEx and get 15 free compilations per month on the Free plan — no credit card required.
Related Articles
- Getting Started with FormaTeX — Step-by-step guide to creating your first API key and making your first compilation request
- The FormaTeX Security Model — How FormatEx sandboxes LaTeX execution to prevent shell injection and unauthorized file access
- LaTeX API Error Codes: Complete Guide — Full reference for 401, 403, 422, 429, and all other API error responses
- Compiling LaTeX in CI/CD Pipelines with FormatEx — How to securely inject API keys into GitHub Actions and GitLab CI workflows
- LaTeX API Rate Limiting and Retry Logic — Exponential backoff, jitter, and queuing strategies to pair with solid auth handling
\end{article}
\related{posts}




