Authentication
Simple bearer-style tokens in headers.
The tokens
| Header | Purpose | Configured by |
|---|---|---|
X-Ledger-Token | GET endpoints (all reads) | LEDGER_TOKEN env |
X-Ledger-Admin-Token | POST / write endpoints (imports, jobs, cash-requests) | LEDGER_ADMIN_TOKEN env |
If LEDGER_ADMIN_TOKEN is unset, admin endpoints fall back to accepting the
read token. In prod, always set both.
The check
ledger/auth.py — two Depends() functions:
def require_ledger_token(x_ledger_token: str = Header(...)) -> None:
if x_ledger_token != settings.ledger_token:
raise HTTPException(status_code=401, detail="invalid ledger token")
def require_admin_token(x_ledger_admin_token: str | None = Header(None), ...) -> None:
admin = settings.ledger_admin_token or settings.ledger_token
if (x_ledger_admin_token or x_ledger_token) != admin:
raise HTTPException(status_code=401, ...)
The webhook exception
POST /v1/india/webhooks/glomopay does NOT use X-Ledger-Token. It
authenticates via HMAC-SHA256 over the request body using
GLOMOPAY_WEBHOOK_SECRET. See Webhooks.
CORS
The API allows browser calls from origins listed in LEDGER_UI_ORIGINS:
http://localhost:3000,http://localhost:3100,http://127.0.0.1:3000
Add production origins to the env in Coolify.