0015. The authentication-method and credential-verification model
Context
Issuing a token begins with authenticating the principal — the login ceremony. That ceremony is stateful, may read the strongly-consistent core (it checks a stored credential), and runs at the admission plane (Modgud, ADR-0009). The verification of the resulting token is stateless and core-independent (Vör, ADR-0010). The single most dangerous mistake an identity system of this shape can make is to blur those two — to let the verification hot path consult "did this user authenticate / satisfy MFA?" against some shared store, which is exactly the core-read on the hot path the constitution forbids (ADR-0001 rule 1) and the gravity that re-collapses the design into a monolith. This ADR fixes the authentication-method architecture and, with it, draws that line explicitly.
Decision
-
An
AuthenticationMethodtrait is the pluggable login-ceremony seam at Modgud. v1 ships password (Argon2id) and TOTP. Reserved-with-seats: WebAuthn / passkeys (viawebauthn-rs, already named in ADR-0002's rationale), magic links, social / upstream-IdP federation (the inbound OIDC/SAML-as-relying-party path, ADR-0019), push approval via the authenticator app (proposal 0028), a temporary access pass (bounded onboarding credential, proposal 0028), SMS / voice OTP — supported because the market demands them, but explicitly low-assurance (SIM-swap and interception risk): theiramrvalues are distinct, realm policy may forbid them for step-up, and the risk pipeline (ADR-0031) weights them accordingly, with delivery riding proposal 0011 — and certificate-based authentication (smart card / PIV): the client-certificate ceremony verifies against a realm-configured trust-anchor set with issuance-time CRL/OCSP checking (an issuance-side read, permitted — never a verification- path one), mapping to its own high-assuranceamr/acrvalues; the regulated-workforce method, reserved now because its trust-store schema is realm configuration that must exist before the method can. An authentication policy composes methods per realm (ADR-0012). -
The Modgud↔Vör line, stated. Modgud authenticates: stateful, core-touching (it reads the stored credential — a write rule 2 permits), and session-producing (ADR-0016). Vör verifies: stateless, core-independent, the rule-1 hot path. The boundary is absolute — verification never invokes an authentication method and never reads authentication state.
-
Authentication context travels in the token, not the core. The methods used and the assurance reached — the OIDC
amr(authentication methods reference) andacr(authentication context class reference) claims — are stamped into the signed token at issuance. A relying party or Vör that must enforce "this operation requires MFA" reads it from the signed artifact, never from a core query about the user's recent activity. Assurance becomes a property of the token, which is why MFA (ADR-0020) can be a roadmap feature that bolts on: theamr/acrclaim shape is a reserved seat in the token format (ADR-0003) from v1. -
Credential secrets are core-resident and never hot-path-read. Password hashes, TOTP secrets, and passkey public keys live with the directory (ADR-0011) in the strong core; they are read only during the issuance ceremony at Modgud, never during verification (rule 2). Argon2id parameters and the secret store are custody concerns handled like keys (ADR-0003's
KeyCustodydiscipline applied to credential secrets). -
Adding a method — the extension contract. A new authentication method — a Kerberos-ticket consumer, an LDAP-bind verifier, or a scheme that does not exist yet — is a crate implementing
AuthenticationMethod, admitted on rung 3 of the extension ladder (ADR-0029 decision 6): build-time Cargo composition, never dynamic loading. Every method satisfies the same five obligations:- a ceremony — steps over
SessionStorestate (challenge/response, redirects); the trait is ceremony-shaped precisely so unknown future methods fit it; - a credential record type — schema-versioned, stored apart from the principal (ADR-0011 decision 2), read only at issuance (decision 4);
- an
amrregistration and an assurance mapping into realmacrpolicy (ADR-0020) — the only face the rest of the system ever sees, which is why a new method changes nothing downstream of issuance; - abuse-case tests as an admission requirement (ADR-0027, ADR-0028) — a method is an attack surface, and an in-tree method lands with its security review and its attacks asserted to fail;
- composition wiring in
vord-serverand per-realm policy exposure (ADR-0012).
In-tree methods are upstream contributions under that review bar; out-of-tree methods are operator-built
vord-servercompositions carrying the extra crate — possible by construction, unsupported by default. Tenants never supply methods: a tenant's custom credential store is reached by federation (ADR-0019 — front it with anything speaking OIDC/SAML) or, during migration, by the JIT legacy verifier (proposal 0014); the Wasm tier (ADR-0029) gates and enriches ceremonies but never conducts one.A method MAY consume an external protocol as its verifier — LDAP bind-as-user against an operator directory, SPNEGO ticket validation against a keytab — without colliding with ADR-0047, which declines serving those protocols, not consuming them. The cost is named rather than hidden: such a method makes login availability depend on the external system, which an issuance-side dependency is allowed to do (ADR-0010 §3) — verification of already-issued tokens is never touched.
- a ceremony — steps over
Consequences
- The constitution's central risk is closed at its most tempting point: there is no code path by which verification learns "did they do MFA" except by reading the signed token, so the property test of ADR-0010 (verify with the core unavailable) holds even for MFA-gated operations.
- The pluggable-method shape gives Vord parity with Entra/Okta/Auth0 (passwords, TOTP, passkeys, magic links, social) behind one seam, and lets a realm's policy differ (workforce vs CIAM, ADR-0012) without new mechanism.
- How a method is added is now a stated contract (decision 5), so community methods — including the consume-side Kerberos/LDAP verifiers ADR-0047 deliberately leaves unshipped — are additive crates under a known review bar, never architecture changes.
- Stamping
amr/acrinto the token is what makes step-up authentication (ADR-0020) and FAPI-grade assurance (ADR-0025) expressible without a stateful enforcement read — the token carries the proof. - The login ceremony's latency is an issuance-side budget, distinct from verification latency, and is measured as such (the architecture's quality scenarios) — a core outage degrades new logins, never existing verification (ADR-0010 §3).