Authentication
Version stamp
Applies to:
renvor0.0.0 · framework source 7d0816a · MSRV 1.94.0 · documentation set pre-releaseThis stamp is a single shared partial (
docs/_stamp.mdx) imported by every prose page and the API reference. It binds this documentation snapshot to the immutable framework commit it describes. The framework remains unpublished and no release compatibility promise applies.
renvor-auth and renvor-auth-http are implemented and tested, but renvor does not depend on
either crate. There is no published or supported installation path while the crates remain
unpublished.
Domain first, transport second
renvor-auth names no router or status code. It owns subjects, credentials, sessions, tokens,
authorization policies, abuse limits, and audit events. renvor-auth-http is the adapter that
joins those operations to renvor-http; it implements no second copy of the policy decisions.
The HTTP adapter registers these routes:
| Route | Purpose |
|---|---|
POST /auth/register | Register a credential without overwriting an existing account |
POST /auth/login | Establish an opaque cookie session |
POST /auth/logout | Revoke the presented session |
GET /auth/me | Read the authenticated subject |
POST /auth/verification/resend | Request another verification message |
POST /auth/verification/confirm | Consume a verification token |
POST /auth/password/forgot | Acknowledge recovery without revealing account existence |
POST /auth/password/reset | Consume a recovery token and replace the credential |
POST /auth/token/refresh | Rotate a refresh token; present only with the tokens feature |
Password and account guarantees
- Password length is measured in Unicode code points after NFC normalization. The default range is 15–256, with no composition rule and no truncation.
- Passwords are hashed with Argon2id using RFC 9106's second recommended parameter set.
- Unknown-account and wrong-password login paths perform equal credential work; the contract does not claim constant execution time.
- Duplicate registration cannot replace the existing credential.
- Verification and recovery tokens are single-use and stored only as digests.
- A delivery failure is visible to the operator without changing the response that could reveal whether an address has an account.
Cookie sessions
The session cookie is named __Host-rv_session and is emitted with Secure, HttpOnly,
Path=/, and either SameSite=Lax or SameSite=Strict. SameSite=None is not representable.
The server stores only a digest of the opaque identifier.
The default session policy is 30 minutes idle, 12 hours absolute, and a target bound of five live
sessions. That last bound is enforced per login rather than atomically: two simultaneous logins can
briefly leave six live sessions, and the next login corrects it. The configuration API refuses time
windows outside its NIST AAL2 ceilings rather than silently clamping them. Cookie-authenticated
unsafe requests require a CSRF token bound to the session; among the routes above, that currently
means POST /auth/logout.
Policy, abuse control, and audit
Authorization is deny-by-default and enforced inside application operations. Anonymous callers,
missing resources, insufficient scopes, and policy refusals all return one NotPermitted result,
so the decision does not reveal whether a resource exists. Token scopes are checked before the
policy at the same operation boundary.
Seven state-changing flows are abuse-bounded: registration, login, both verification operations,
both password-recovery operations, and token refresh. The counter space has a finite row bound;
logout and GET /auth/me are intentionally outside it because they only revoke or read the
caller's own state.
Permit and refuse paths both write the same closed audit-event shape. The vocabulary contains no arbitrary text field, and a sink failure refuses the operation on either path. The included sink only records events for tests; Phase 010 owns production observability adapters.
Optional access and refresh tokens
The tokens feature enables signed JWT access tokens and opaque refresh tokens. The verifier owns
the accepted algorithm; a token's header cannot select it. Keys come from a bounded local ring,
and remote key URLs and critical extensions are refused.
Refresh rotation is one database transaction. A replay revokes the complete token family, and the family owns an immutable scope grant. The SQLx and SeaORM implementations run the same concurrency contract on PostgreSQL and MySQL.
Deliberate limits
- A password reset revokes neither existing sessions nor refresh-token families.
- Password rehash-on-login is not wired:
needs_rehashhas no production caller. - Signing keys have no rotation path; the Phase 009 threat model records this as unmitigated.
- There is no route that issues the first access/refresh pair.
- The included mail and audit sinks are deterministic recording sinks, not SMTP or production telemetry adapters.
- No authentication UI or generator integration exists.
- Persistence and authentication are not yet wired through the
renvorfacade.
These are retained limits, not hidden capabilities. The complete list is in the Phase 009 limitations record.