| app | ||
| tests | ||
| .gitignore | ||
| env.example | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
Atlas — scoped machine-token API
Atlas is the operator CRM / customer ledger behind Seglamater: one place that tracks each customer, the products they run, the deployments phoning home, and the subscriptions that bill them. A FastAPI + async SQLAlchemy + Postgres service.
This repository is a curated architecture showcase — a focused, self-contained extract of Atlas's authentication and authorization core, published so the design can be read end to end. It is not the whole product: the HTML operator console, the background ingest workers (endpoint liveness poller, release-manifest watcher, billing ingest, digest), and the derived business analytics are omitted so the extract stays centered on the part worth showing — how automation gets least-privilege, revocable, auditable access to the ledger.
The problem
Atlas needs to be driven two ways: by a human operator through an SSO-fronted console, and by automation — scripts and AI agents that register deployments, sync subscriptions, and read fleet state without a human in the loop. Handing automation the operator's session would give a leaked credential the run of the whole CRM, including destructive operations. The machine-token API exists to make automation access narrow, bounded, and revocable by construction.
Architecture
Scoped machine tokens (app/tokens.py, app/auth.py)
- 256-bit bearer tokens. Minted from
secrets.token_urlsafe(32)behind anatlas_sk_prefix so a leaked string is recognizable to a secret scanner. - Stored SHA-256-hashed, never in plaintext. Only the hash and a short display prefix are persisted; the full secret is returned exactly once at creation and never logged or shown again. Because the token is high-entropy, a fast hash with an indexed by-hash lookup is the right choice — no per-request password comparison.
- Least-privilege scope allowlist. Tokens carry a subset of a fixed allowlist of
<noun>:<verb>scopes (customers:read,deployments:write, …). There is deliberately no delete scope and no token-management scope — deletes and token issuance stay interactive-admin-only and are unreachable by any token, so a leaked key can neither destroy data nor mint more tokens. - A token is never an admin. Admin-only routes depend on
require_admin, which a token can never satisfy — the privilege boundary is structural, not a scope check.
Customer-bound, read-only tokens (app/auth.py)
A token may be bound to a single customer. A bound token is read-only and fleet-blind: it is rejected on every write and every aggregate/list endpoint, and passes only the per-customer read gate — the structural least-privilege shape for a customer-portal "my account" backend.
The binding is enforced after the row is fetched, and a request for a customer the token doesn't own returns 404, not 403 — a foreign-but-existing customer is made indistinguishable from a nonexistent one, so the status code can't be used as a slug-enumeration oracle.
Per-token rate limiting (app/tokens.py)
An in-memory fixed-window limiter caps each token's request velocity, bounding how fast a leaked token can be abused before it is revoked. It's a velocity cap, not a security boundary on its own; the map is kept bounded by evicting rolled-over windows.
Defense-in-depth around the edges
- Trusted-upstream header gate (
app/auth.py). In production Atlas sits behind a reverse proxy that injectsX-Authentik-*identity headers. Those headers are trusted only from a configured, narrow trusted-net — otherwise any co-located container or direct caller could spoofX-Authentik-Groups: atlas-adminand bypass the proxy. The shipped default fails closed to loopback only. - App-layer group check. A valid upstream session isn't enough to read the CRM: the human must also be in an allowed group, asserted at the app layer rather than delegated entirely to the IdP binding.
- Signed double-submit CSRF (
app/security.py). Stateless HMAC-signed CSRF tokens with a__Host-cookie prefix protect the operator write forms without a server-side session store. - Write attribution / audit trail (
app/services/audit.py). Every mutation — including machine-token writes — emits an append-only state event recording who changed what, with PII kept out of the audit record by design. - No anonymous schema disclosure. The interactive API docs are off by default, so a deployment without a proxy in front doesn't anonymously publish its full API surface.
Layout
app/
tokens.py token minting, SHA-256 hashing, scope allowlist, rate limiter
auth.py request identity resolution + the scope/binding gates
security.py signed double-submit CSRF
config.py environment-driven settings
db.py async SQLAlchemy engine / session factory
models.py ORM models (customer, deployment, subscription, api_token, ...)
schemas.py Pydantic request/response shapes
main.py app assembly (routers + CSRF middleware + health)
api/
tokens.py admin-only token lifecycle (mint / list / revoke)
customers.py fleet + per-customer reads, scoped writes, admin delete
deployments.py scoped read/write
subscriptions.py scoped read/write
services/
token_admin.py the DB write-path for token issuance / revocation
audit.py the operator-mutation audit trail
tests/ the security-critical unit + integration tests
Tests
The security-critical logic is unit-tested without a database (the repo's pure-function norm): the token primitives and scope allowlist, the scope/binding authorization gates, the trusted-net parsing, and the CSRF crypto + middleware.
pip install -e ".[dev]"
pytest
License
AGPL-3.0-only — see LICENSE for the full text.
A commercial license is available for use outside the AGPL-3.0 terms — contact Info@Seglamater.com. (Formal commercial-license terms are being finalized.)
Versions previously published under the Business Source License 1.1 remain available under BSL-1.1.
Copyright © 2026 Seglamater Services LLC.