Files
skills/docs/api-stack/api/api-plugin-auth/src/middleware/require-auth.md
2026-05-29 08:20:56 +01:00

2.4 KiB

middleware/require-auth

Purpose

requireAuth() is the canonical Hono middleware factory for gating a route or sub-route on an authenticated principal. It reads c.get("user") and, if the value is null (or absent), throws AuthError(AUTH_UNAUTHENTICATED) carrying context.statusCode: 401 so the @suaveplan/api error-handler middleware translates it to an HTTP 401 response.

Features

  • Depends only on the typed c.get("user") slot installed by sessionMiddleware — no dynamic service lookup, no per-request Better-Auth call.
  • Single failure mode: AUTH_UNAUTHENTICATED with statusCode: 401 attached to the error context.
  • Idempotent — applying the middleware twice in the same chain costs one type narrow + one truthy check.

Usage: Basic

import { requireAuth } from "@suaveplan/api-plugin-auth/middleware/require-auth";

app.use("/private/*", requireAuth());
app.get("/private/me", (c) => c.json(c.get("user")));

Usage: Advanced

Compose requireAuth with requireRole and requireEmailVerified to build a sliding scale of access controls. Each middleware throws its own typed AuthError, so the error handler can emit specific OpenAPI 4xx responses per stage:

import {
    requireAuth,
    requireRole,
    requireEmailVerified,
} from "@suaveplan/api-plugin-auth/middleware";

app.use("/admin/*", requireAuth(), requireRole("admin"));
app.use("/billing/*", requireAuth(), requireEmailVerified());

API Reference

function requireAuth(): MiddlewareHandler

Returns a Hono middleware handler. Throws AuthError(AUTH_UNAUTHENTICATED, "Authentication required", { context: { statusCode: 401 } }) when c.get("user") is null or undefined. Calls next() otherwise.

Implementation Notes

  • The check uses === null || === undefined rather than a truthy check so a fully-populated Principal with falsy values (e.g. email: "" after the principal mapping normalised it out) still passes. Principal objects are never falsy.
  • Throwing — not returning a 401 response directly — keeps the error shape consistent with requireRole and requireEmailVerified; all three flow through the @suaveplan/api error-handler, which both serialises the error envelope and emits the OTel span event.
  • The statusCode: 401 field is read by the error-handler middleware installed by @suaveplan/api; the auth plugin does not own status mapping itself.