Guides / Recovery
Email verification and account recovery.
Operate non-enumerating Tenant Member verification, reset, and invitation delivery without leaking one-time proofs.
Public request resources
POST /v1/console/email-verification-requests and POST /v1/console/password-reset-requests accept an email and return the same 202 acknowledgement whether the account exists, is already verified, is disabled, or is unknown. Source-IP and normalized-identity policies are stored in PostgreSQL and shared across replicas.
For an eligible member, creating a request locks the membership, revokes prior unused proofs of the same kind, creates a new high-entropy hashed proof, encrypts the recipient and link payload, and schedules email delivery in one transaction. Verification proofs last 24 hours; reset proofs last 30 minutes.
Consume a proof
Email links carry the proof in a URL fragment. The console removes it from browser history and submits it only in a JSON body to POST /v1/console/email-verifications or POST /v1/console/password-resets. Proofs are one-time and never stored in plaintext.
Email verification marks ownership but does not create a session. Password reset is also the explicit lost-authenticator recovery boundary: it replaces the password, consumes outstanding login attempts and authorization codes, revokes every management session and server-tracked OAuth access token, and deletes every Tenant Member management WebAuthn credential. The next password-verified login must enroll a fresh passkey or security key before management access is restored.
Recovery trust decision
Email is not a routine authentication factor, but control of the reset mailbox is the baseline’s ultimate recovery factor. That is a deliberate, high-impact trust decision: a compromised mailbox can reset the password and replace every authenticator. Production operators should require strong mailbox security, alert on tenant_member.authentication_recovered, and document who can recover or suspend the email account. Recovery codes or an operator-assisted process should be added only as separately modeled, revocable resources with clear issuance and replacement semantics.
Invitation delivery
Tenant invitation creation remains idempotent, but its acceptance proof is no longer returned to the administrator. ComplicatedAuth queues the seven-day fragment link directly to the invited address and returns only safe invitation metadata. An exact API replay does not create another invitation or email delivery.
Email operations
Configure EMAIL_SMTP_ADDRESS and EMAIL_FROM. Production authentication additionally uses EMAIL_SMTP_USERNAME, EMAIL_SMTP_PASSWORD, and EMAIL_SMTP_STARTTLS=true. EMAIL_DELIVERY_TIMEOUT defaults to 15 seconds.
Delivery is asynchronous and at-least-once. Workers use database leases, bounded exponential retry with jitter, and dead-letter exhaustion. A stable message ID helps downstream systems correlate duplicates, but SMTP cannot make an ambiguous post-DATA disconnect exactly once. Templates therefore reuse the same one-time link safely. Alert on delivery age, retries, and dead letters without logging recipients or links.
Failure posture
- A request is acknowledged only after its database lookup; rate-limit dependency failure returns
503. - An unknown address never creates a token, delivery, job, or account-specific response.
- A disabled member cannot receive or consume a new proof.
- A successful password reset never creates a bootstrap or strong session.
- Changing SMTP configuration does not affect the public API contract.
- Operators may inspect safe delivery and job state, but never the encrypted recipient, proof, or link.