Early alpha Chronicler is pre-release software and changes often. Join the waitlist
Architecture

Authentication & Identity

How a caller proves who they are, and how an account carries a name, a face, and its login methods - and why each piece works the way it does.

Before Chronicler can decide whether you may do something, it has to know who you are. That is authentication, and it runs before everything else. A request arrives with a bearer token, middleware verifies it, and the verified principal is put on the request context. From that point on, every layer reads the same principal. This page is about how a caller gets that token, and how an account carries the rest of its identity.

Two ways in, one account

A user can sign in with a password or with an external provider such as Google. Provider login uses the standard OAuth Authorization Code flow with PKCE, which is the modern way to do it without a shared secret sitting in a browser.

There is one awkward moment in provider login worth explaining. The provider sends the user back to Chronicler as a browser navigation, but Chronicler hands out tokens in a response body, not in a redirect. Putting a token in the callback URL would leak it into browser history and server logs, so instead the callback carries a single-use handoff code, and the app trades that code for the real tokens. The token never rides in a URL.

A second question is what happens when the same person signs in two different ways. Chronicler links a provider account to a Chronicler account by a stable provider subject and a verified-email rule, so two logins that share a verified email land on one account rather than quietly creating two.

Email verification, passwordless login, password reset, and the OAuth handoff all look different to a user, but underneath they are the same thing: a one-time token that proves the holder controls something. Chronicler builds them on a single one-time-token primitive, so the security-sensitive mechanics are written once and tested once, instead of being reinvented, slightly wrong, in each feature.

Sessions get the same care. A session can be revoked immediately through a per-family liveness check, a user can list their own sessions and end one, and a refresh token that is replayed is detected and rejected.

A handle, a name, and a login

An account carries three separate things that are easy to confuse. The username is a global, unique, stable handle. It is what invites, links, and mentions point at, so it has to be stable. It is assigned automatically at registration, because forcing a new user to invent a unique handle at signup is friction for no reason, and it can be changed later, freeing the old one at once. The display name is freeform and only for presentation. The email is for login. Keeping them apart means a user can rename themselves without breaking every link that pointed at them.

A face, worked out at read time

Rather than store one avatar field, Chronicler resolves an avatar through a fixed ladder, checked in order: an uploaded image, then a provider photo by rank, then Gravatar if the user opted in, then an initials monogram. The user's deliberate choices are real domain state in a preferences aggregate. The provider photo, on the other hand, is treated as cached reference data, refreshed on login and never event-sourced, because it belongs to the provider and can change without telling us.

Fresh proof for dangerous actions

A logged-in session is proof that you signed in, once, maybe hours ago. It is not proof that you are still the person at the keyboard. For a dangerous action, that gap matters, so step-up authorisation, a sudo mode, asks for a fresh re-proof of identity. The re-proof is recorded server-side as a short-lived grant tied to the session, not handed to the client as a token it has to carry and could lose. One guard reads that grant, and the same guard protects changing your MFA, changing billing, and impersonating a user.

Multi-factor authentication is what makes the strong proof strong. A user can enrol an authenticator app, an email code, and single-use recovery codes, with one primary factor and the rest as fallbacks. The authenticator secret is stored as an encrypted, crypto-shreddable event field, so erasing an account destroys it along with everything else.

Identities that are not people

Two kinds of principal are not a human at a keyboard. A service account is a machine user owned by a workspace. It cannot sign in, holds its own roles, and authenticates through a scoped API token whose real power is the overlap of its owner's live roles and its own narrower scope. It can never touch a denied capability and never acts as an administrator, so a leaked automation key is bounded by design.

The system account is the installation itself acting as a user, real but with no password, minted on first run. It is what shows up as the actor when the platform, rather than a person, did something.

And sometimes support staff need to see exactly what a user sees. Impersonation gives an authorised operator a read-only view as another user, with the real operator kept named in the audit trail, so the convenience never becomes an untraceable back door.

Where this connects

Knowing who someone is only sets up the next question. Authorization decides what they are allowed to do.

Read the record for the detail

This page is the guide. The full records under docs/adrs carry the exact token lifetimes, the linking rules, and the alternatives that were weighed and rejected.