# Architecture One-Pager

*Passkey Authentication Service · Solution Architecture v1.0 · open source, self-hosted on Kubernetes · Security & Identity Architecture · 2026-10*

**Ceremony state is ephemeral and region-pinned; credential state is durable and globally replicated; the authentication hot path touches nothing else.**

Every major consumer service now offers to sign you in with a passkey, and the cryptography behind that button is settled: WebAuthn specifies the ceremony, the authenticator holds a private key that never leaves it, and a phishing site cannot produce a valid assertion for a domain it does not control. None of that is the hard part. The hard part is everything the specification deliberately leaves to the relying party, and it is where passwordless deployments actually fail. Where does the five-minute challenge live, and what consumes it exactly once? What happens to the user who has one passkey and drops their phone in a lake — in a system that has, by design, no password to reset? Is a signature counter that moved backwards a cloned authenticator or a synced passkey behaving exactly as its vendor intended, and which answer locks out more people? When does a platform get to say the password is gone, and who absorbs the support calls that claim produces? This package is the architecture for a multi-tenant service that answers those questions for forty relying parties, at a scale where each answer has a cost somebody pays.

The design rests on one boundary. The ceremony — a challenge written, read once and discarded inside five minutes — is region-pinned, strongly consistent and never replicated. The credential record — a public key that must outlive every component in the system — is globally replicated, read-mostly, and read-only from the login path. Nothing else on that path is a durable write, which is what makes a 60 ms p99 reachable with no distributed transaction anywhere in a login, and what makes every dependency's failure a declared degradation rather than an outage: credential store unavailable fails closed, risk engine unavailable fails open with the verdict marked unevaluated, metadata feed unavailable fails static on the last signed snapshot. Authenticator trust is decided once at registration and written down as an immutable verdict, so the authentication path is pure cryptography against a recorded decision and the metadata feed is not a login dependency. The platform returns a signed, short-lived, single-use verdict and never issues a session, which bounds what a compromise of it costs a tenant. And because a passwordless account's real security is set by whichever route gets a locked-out user back in, every recovery route carries an assurance classification into the verdict, must end with a working credential, and earns the new credential a cooling-off period before it may revoke anything the attacker would want gone.

## What it is, and what it is not

- **A verifier of assertions against recorded decisions** — not An evaluator of policy on every login
- **A holder of public keys and verification material** — not A custodian of authentication secrets
- **An issuer of short-lived signed verdicts** — not An identity provider that issues sessions
- **Two stores split by the lifetime of their data** — not One store with one consistency model
- **A platform where recovery is a first-class authentication route** — not A platform where recovery is an exception handler
- **A consumer of a signed metadata snapshot** — not A caller of a metadata service on the hot path
- **A gate that refuses a cutover without the coverage figure** — not An arbiter of when a tenant's password should go
- **An RP ID on a domain the tenant owns** — not A convenient trust anchor on the platform's domain
- **A system where revocation is a state change** — not A system where revocation is a deletion

## The decisions that are the architecture

1. **Ceremony state ephemeral and pinned; credential state durable and replicated** (ADR-01) — Two kinds of state with nothing in common but the word store. One retry's worth of loss on one side, a locked-out human on the other, so each gets the guarantee it actually needs.
2. **A challenge is consumed in a store, not carried as a token** (ADR-02) — A signature proves issuance; only a record proves use. A stateless challenge needs a nonce table to be safe, which is the same state with worse ergonomics.
3. **Tenant policy is read from memory, never from the control plane** (ADR-03) — Configuration read a billion times and written ten times belongs next to the reader. It is also the only way logins survive a total management-plane outage.
4. **Authenticator trust is admitted once and recorded immutably** (ADR-04) — Attestation is not resent with an assertion, so evaluating it per login means putting an external feed on the hot path and making the same credential's fate depend on publication timing.
5. **The metadata snapshot is signature-verified and fails static** (ADR-05) — Tolerate unavailable generously; refuse untrusted absolutely. An unsigned fresher copy is strictly worse than a signed older one.
6. **The sign counter is recorded and alerted on, enforced only by choice** (ADR-06) — Synced passkeys legitimately report zero. Strict enforcement does catch clones, and locks out far more people whose authenticator is working as designed.
7. **Fail closed on identity, open on advice, static on reference data** (ADR-07) — Three different questions deserve three different answers. A platform that gives all three the same answer is wrong twice, and the wrong answer was chosen by whoever wrote the catch block.
8. **Shed challenge issuance before assertion verification** (ADR-08) — A user who has already touched their sensor has done work the platform paid for. Refusing that is both the most wasteful shed and the most confusing failure.
9. **In-flight ceremonies are abandoned on failover, never migrated** (ADR-09) — Replicating disposable state makes single-use consumption probabilistic during exactly the conditions nobody can reason about. Price the retry instead.
10. **Every recovery route is classified and must end in a credential** (ADR-10) — An account protected by a passkey and recoverable by an emailed link is an account protected by an emailed link. The platform's job is to label that and carry the label forward.
11. **A recovery-enrolled credential waits before it may revoke** (ADR-11) — Recovery and revocation compose into an eviction attack. The attacker needs it immediate; the honest owner almost never does.
12. **The platform issues verdicts; the relying party issues sessions** (ADR-12) — Producing evidence is cheaper to be wrong about, and far cheaper to be breached with, than producing authority.
13. **Revocation is a state change; a policy change is never retroactive** (ADR-13) — A statement about the future and an act on the present need different blast radii. Share a mechanism and the quieter one eventually does the louder one's damage.
14. **One tenant-owned RP ID, with related origins for brands** (ADR-14) — Whoever owns the namespace a credential is scoped to decides whether the tenant can ever leave. A convenience RP ID on the platform's domain is a migration they cannot perform.
15. **The cutover is gated on measured two-or-more coverage** (ADR-15) — Below a threshold, switching the password off is a support incident with a security press release. Do not block the decision; block it being made without the number.

## Why this should still be right in ten years

The store, the mesh, the proxy, the HSM and probably WebAuthn's own successor will all be replaced inside this platform's life. These five properties are the ones that should survive the replacement, and each is a statement about where something lives rather than about what it is built from.

- **State is separated by lifetime, not by subject.** A record whose loss costs a retry and a record whose loss costs an account do not belong in the same store under the same guarantee, whatever the data model suggests. The value of that separation grows with scale rather than shrinking, because the cost of over-guaranteeing the disposable half is paid on every single operation.
- **The expensive judgement happens once and leaves an artefact.** Registration resolves authenticator trust against external evidence and records what it decided, against what, and how stale that evidence was. Authentication checks the artefact. The same separation underlies signed build attestations, credit decisions and visas, and it survives every change of metadata format and authenticator technology.
- **Each dependency's failure direction is written down.** Classifying dependencies by whether their absence makes the answer wrong or merely less informed is independent of what the dependencies are. The alternative is not an absence of policy; it is a policy chosen by a timeout default, which is how an advisory component takes a product down.
- **The platform produces evidence, not authority.** A short-lived verifiable statement about what happened is a fundamentally smaller thing to breach than the power to act. The token format will change several times; the distinction between a notary and a bank will not.
- **The weakest entry path is measured and labelled.** Strengthening the front door while leaving the recovery path unlabelled relocates the security rather than raising it. Carrying the route's strength into the decision that consumes it is the only mechanism that lets anyone downstream act on the difference, and it will matter for as long as humans lose devices.

## Non-functional targets

Every figure below is a stated assumption. They are listed with the mechanism that is supposed to deliver them and the view where that mechanism is drawn, so a reviewer can disagree with the number and the means separately.

| Quality | Target | How it is met | View |
|---|---|---|---|
| Authentication availability | ≥ 99.99% monthly | Stateless verification replicas across three zones, region-pinned ceremony state, no control-plane dependency on the hot path | 16 |
| Management plane availability | ≥ 99.9% monthly | Deliberately lower: a console outage must not be able to affect logins, and is not treated as one | 08 |
| Assertion verification latency | p50 ≤ 15 ms, p99 ≤ 60 ms | One atomic local consume, one local credential read, policy from replica memory, signing off the critical section | 13 |
| Challenge issuance latency | p99 ≤ 25 ms | One strongly consistent single-key write to the region-pinned ceremony store | 13 |
| Registration finalisation latency | p99 ≤ 120 ms | Attestation verification against an in-process snapshot, plus a cross-region quorum write for the credential | 14 |
| Steady throughput | 20,000 ceremonies/s per region | 24 verifier and 12 issuer replicas per zone, horizontally scaled with no ceremony affinity | 16 |
| Burst | 5× for 120 s | Phase-ordered shedding at the edge: challenge issuance refused before assertion verification | 18 |
| Credential volume | 400 M records, ~480 GB | Regional-by-row partitioning by tenant and user handle; growth served by adding partitions | 11 |
| Ceremony state | TTL 300 s, ~6 M live at peak | In-memory, TTL-reclaimed, no cleanup job and no backup | 11 |
| Audit volume and retention | 2.5 B events/yr; 13 months hot, 7 years cold | Buffered stream into a columnar store, aged into hash-chained archive segments | 10 |
| RPO — credential records | 0 | Required, not assumed: synchronous quorum across three zones. A lost row is a locked-out human | 16 |
| RPO — audit stream | ≤ 5 s | Buffered emission that never backpressures a ceremony | 10 |
| RTO — regional failover | ≤ 60 s | Ingress withdrawal and capacity ramp only; no ceremony-state recovery step exists | 16 |
| Global credential convergence | p99 ≤ 2 s | Read-your-write in the registering region, bounded replication elsewhere, documented in the API contract | 11 |
| Platform-attributable ceremony failures | ≤ 0.05% | Measured on ceremony outcome codes, excluding user abandonment and authenticator-side cancellation | 18 |
| Recovery completion | ≥ 95% within 10 min | Three self-service routes with per-route cool-off; the operator-attested route is excluded from this measure | 15 |
| Verdict lifetime | 60 s, single use, one audience | HSM-signed, nonce-bound, audience-bound to one RP ID, verified offline by the relying party | 21 |

## Scope

**In scope**

- Relying-party onboarding: tenants, RP IDs with verified domain control, explicit origin allowlists, and a staging environment whose credentials cannot authenticate against production
- Versioned per-tenant authentication policy — user verification, attestation conveyance, resident-key requirement, authenticator attachment, counter mode, ceremony timeout — with pre-flight impact analysis and forward-only application
- Registration ceremonies with excludeCredentials, attestation verification against a signed snapshot, and an immutable admission verdict written atomically with the credential
- Authentication ceremonies for both discoverable and identifier-first flows, with single-use challenge consumption and full verification of client data, origin, RP ID hash and flags
- Credential lifecycle: a human-readable device list, labelling, revocation as a state change, the last-credential guard, bulk revocation under second-approver control, and re-evaluation of stored verdicts against metadata compromise notices
- Account recovery across four routes with assurance classification carried into the verdict, mandatory credential enrolment, per-route cool-off windows and operator attribution
- Risk signals attached to the verdict, enumeration-resistant identifier-first responses, and phase-ordered load shedding
- Migration from passwords: enrolment offers after a legacy login, three coverage figures per tenant, and a cutover gated on a tenant-acknowledged threshold
- Signed verdict issuance and published verification material, with sessions remaining the relying party's responsibility
- Append-only, hash-chained audit of every ceremony outcome, lifecycle action, recovery attempt and policy change, with tenant-pullable export

**Explicitly out of scope**

- Authorization, entitlements and role management — the service authenticates; the relying party authorizes
- Password storage and verification, which stays with the relying party for the migration window and is then removed by them
- Session issuance, session lifetime, logout, session revocation and step-up decisions
- Enterprise directory synchronisation and user provisioning
- The relying party's own sign-in user interface and copy, beyond the ceremony SDK
- Fraud and abuse decisioning beyond the signals attached to a verdict

## What a four-week prototype should prove

The prototype's job is to falsify the three claims the whole design rests on — that single-use consumption really is cheap enough to sit on the hot path at rate, that a regional failure really does cost only a retry, and that recovery really can end in a working credential without the support desk becoming the authenticator. Everything else in the package can be adjusted; if any of those three is wrong, the boundary in ADR-01 has to move.

1. One tenant with two RP IDs and a related-origin declaration, so both the single-brand and multi-brand origin paths are exercised rather than assumed
2. Two regions with independent ceremony stores and one credential cluster with regional-by-row placement, because the failover claim cannot be tested in one region
3. A mixed authenticator population: synced platform passkeys reporting a zero counter and device-bound security keys reporting a real one, so all three counter modes meet real inputs
4. Three recovery routes wired end to end, including the one-time code and an out-of-band channel, with the cool-off window enforced rather than configured
5. Fault injection for each declared degradation: credential store, ceremony store, risk engine and metadata snapshot, each failed independently
6. An HSM or software PKCS#11 token in the verdict-signing path, so signing latency is measured rather than modelled

- Two concurrent finish calls for one challenge are served by different replicas in the same region: exactly one succeeds, and the loser receives a replay rejection rather than a generic error, at 20,000 ceremonies per second
- A region is killed mid-ceremony under load: in-flight clients receive the restart-the-ceremony error and complete on the second attempt, the surviving region absorbs both the new load and the retry burst, and no challenge is consumed twice
- A credential is registered in one region and a login is attempted in the other within 100 ms: it fails, the failure is the documented convergence error rather than an invalid-credential error, and it succeeds within the 2-second target
- The metadata snapshot fetch fails for seven consecutive days: registrations requiring attestation continue, every resulting verdict records a growing snapshot age, and an unsigned substitute is refused at every attempt including under a forced retry
- The risk engine is slowed past its 15 ms deadline: ceremonies complete, every verdict carries unevaluated rather than a clean score, and an SDK that ignores the field is shown to produce a silently weaker decision
- A recovery is completed by a second party who immediately attempts to revoke the owner's credential: the revocation is refused for the configured window, the owner is notified, and the owner's own credential retains full rights throughout
- A policy tightening that would lock out 8% of a tenant's population is submitted: the impact-analysis gate refuses it, the override requires a named actor, and the attributed override appears in the audit trail within one second

## Open risks, carried rather than hidden

| Risk | If it lands | Response |
|---|---|---|
| The ceremony store becomes the platform's single point of failure in each region | ADR-07 fails logins closed when it is unreachable, so a Redis incident is a regional authentication outage with no graceful degradation available | Treat it as a tier-0 component with its own capacity headroom, zone spread and failover rehearsal; keep the restart-the-ceremony error path exercised so the failure is a retry storm rather than a support storm |
| Re-evaluation of stored admission verdicts produces a queue nobody works | The window ADR-04 and ADR-05 deliberately accept never closes, and the platform's attestation story becomes a registration-time formality with no follow-through | Make the raised-credential count a reported signal with an owner and an age distribution, not a work list; a non-zero count older than a threshold is an alert rather than a backlog |
| Relying parties ignore the assurance level and the unevaluated risk field in the verdict | ADR-10 and ADR-07 both become decorative: a weak recovery grants the same access as a hardware passkey, and a risk engine outage silently weakens every decision | Make both fields mandatory in the SDK's typed result rather than optional reads, publish per-tenant conformance reporting, and treat a tenant that never varies behaviour on assurance as an integration defect to raise |
| Tenants set meaningless cutover thresholds and clear their own gate | ADR-15's control becomes theatre, the password is switched off at low coverage anyway, and the recovery path absorbs a load it was not sized for | Report the threshold alongside the coverage and the resulting recovery volume per tenant, so the next cutover conversation starts from the last one's measured cost rather than from its announcement |
| The cooling-off window is routinely overridden by support under pressure | ADR-11's protection evaporates exactly in the cases it exists for, since an attacker's best move is to call support and claim urgency | Make the override a named, two-approver action with its own audit event and a monthly count; an override rate above a threshold is a process failure to investigate rather than a configuration to loosen |
| A single-credential population never becomes a two-credential population | Every lost device becomes a recovery, recovery cost dominates the platform's marginal economics, and the cutover in ADR-15 is never honestly reachable | Treat two-or-more coverage as the platform's primary product metric rather than enrolment count, and make the second-route prompt at registration a measured conversion funnel with its own owner |

The reasoning behind every component and technology choice is in the [Architecture Decision Record](decision-record): 15 records across 5 areas, each with the alternatives that lost and what the choice costs.
