first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
# middleware/require-email-verified
## Purpose
`requireEmailVerified()` is the Hono middleware factory that gates a
route on the principal's email having been verified. Routes that
trigger sensitive operations (password change, billing portal,
account deletion) use this guard so unverified accounts cannot move
forward without first completing the verification flow.
## Features
- Reads `c.get("user")` directly — no Better-Auth lookup per request.
- Two failure modes: `AUTH_UNAUTHENTICATED` (401) for anonymous
callers and `AUTH_EMAIL_NOT_VERIFIED` (403) for unverified ones.
- Strict boolean check: `emailVerified !== true` fails, so undefined
/ null are treated as unverified.
## Usage: Basic
```ts
import {
requireAuth,
requireEmailVerified,
} from "@suaveplan/api-plugin-auth/middleware";
app.use("/billing/*", requireAuth(), requireEmailVerified());
```
## Usage: Advanced
Use the middleware as a precondition for routes that trigger
high-trust workflows. Combine with `requireRole` so admin routes
require BOTH verified email AND the admin role:
```ts
import {
requireAuth,
requireEmailVerified,
requireRole,
} from "@suaveplan/api-plugin-auth/middleware";
app.use(
"/admin/users/:id/delete",
requireAuth(),
requireEmailVerified(),
requireRole("admin")
);
```
## API Reference
### `function requireEmailVerified(): MiddlewareHandler`
- Throws `AuthError(AUTH_UNAUTHENTICATED)` (401) when `c.get("user")`
is null/undefined.
- Throws `AuthError(AUTH_EMAIL_NOT_VERIFIED)` (403) when
`principal.emailVerified !== true`.
- Calls `next()` otherwise.
## Implementation Notes
- The check uses `!== true` rather than `=== false` so an explicitly
`undefined` / `null` `emailVerified` (which the default principal
mapping should not emit, but a custom mapping might) is treated as
unverified. Failing closed is the right default for an auth gate.
- The middleware does not auto-trigger a re-send of the verification
email — that is the route handler's responsibility once the 403
reaches the client.
- The 403 error carries `context.statusCode: 403` for the error
handler; no other context fields are attached because the principal
identity does not need to be re-emitted on a 403 (it is already
available in the trace span).