Portfolio — the platform
EANNA
one login for every private app — the front door asks Eanna before a request reaches anything
Eanna is the owner’s own code, written for one household and its friends; there is no public sign-up and no public login page. It is the successor to Shambala, the platform behind the previous site. This page describes the design, not the deployment.
What it is
Every private application on this server — the games console today, more tomorrow — needs to know who is asking and whether they may. Eanna answers both questions once, in one place, so that no application has to carry its own accounts, passwords, lockouts or two-factor flows. An app that wants to be protected declares a single grant name; members who hold that grant get in, everyone else gets a polite refusal.
The architecture
-
01
Accounts
Usernames, passwords hashed with a memory-hard function, roles (admin or member), a disable switch, and optional two-factor codes from any authenticator app.
-
02
Sessions
Server-side rows, not signed tokens: the browser holds an opaque, host-only, secure cookie; the server can revoke any session instantly.
-
03
The check
The front door asks Eanna about every request to a protected app. Eanna answers with the user’s name, id and groups — or with a redirect, or a refusal.
-
04
Tickets
A login on the sign-in host becomes a login on the app’s host through a single-use ticket: sixty seconds, one host, one redemption, return address allowlisted.
-
05
Grants
One row per member and app. Adding a protected app is one grant name and one front-door block — nothing inside the app changes.
-
06
Audit
Every login, failure, lockout, ticket, refusal and grant change is a row the owner can read; the admin surface is a command-line tool, deliberately.
How a login travels from the sign-in page to an app on a different hostname without a cookie that spans the whole domain: a one-time ticket, valid for a minute, bound to the exact host it was issued for, redeemed once. The public site never receives a cookie of any kind.
Sessions are rows, not signatures. The previous platform issued one signed cookie that every service read with a shared secret — simple, and exactly the kind of secret that ends up in five places. Eanna was written so that no service holds a secret at all: the front door asks, Eanna answers, and the answer is only trusted where nothing else can reach.
The dashboard. After signing in, a member sees cards for exactly the apps they hold a grant for, plus the public pages; an administrator sees everything. Adding a project to the platform is one registry row and one grant.
The application trusts the identity headers only because it has no other door. Strip them at the front, set them only from Eanna’s answer, and refuse the request if they are missing — so a misconfigured front door fails closed instead of open. That invariant is a unit test.
Feature highlights
-
One login
Sign in once; every private app you hold a grant for opens without another password.
-
Lockout
Five failures lock the account for a while; the correct password does not help until the clock runs out.
-
Two-factor, optional
Enrol with a QR code, confirm with a code, disable with password and code.
-
Host-only cookies
No cookie is valid anywhere but the host it was set on; the public site gets none at all.
-
Instant revocation
Disable a member and every session they had is gone on the next request.
-
Self-service security
Change your password (other sessions signed out), manage two-factor, sign out everywhere.
-
Read-only admin view
Accounts, grants and the app registry at a glance; mutations stay on the command line for now.
-
Tested invariants
Lockout, expiry, ticket reuse, wrong-host tickets, open-redirect attempts and the fail-closed check run before every deployment.
How it was built
Eanna was specified before it was built: the contract of the first protected app was written and reviewed as a document, then implemented against a test list, and it grew its login surface only on private hostnames, by rule.
The dashboard came second, ported from the previous site’s member area onto the same design — server-rendered this time, with no client script beyond a menu toggle.
Tech stack
- Python
- FastAPI
- PostgreSQL
- Alembic
- Argon2
- TOTP
- Jinja templates
- Caddy forward authentication
- pytest
- Claude (planner/executor loop)
Closing note
Eanna — one login for one household. No sign-up, no public login page — deliberately.