---
title: "Middleware"
description: "Nitro middleware in server/middleware/ — what it is, how to write your own, and how the built-in auth guard works."
---

# Middleware

Middleware is code that runs on every incoming request before it reaches a route handler. It sits between callers and routes, making it the right place for cross-cutting concerns: authentication, logging, CORS headers, rate limiting, or anything that needs to apply regardless of which route handles the request.

<Diagram id="doc-block-server-middleware-1" title="Where middleware runs" summary="Middleware intercepts every request before it reaches a route. Allowed requests continue to the route handler; blocked requests get a redirect or error response.">

```html
<div class="diagram-mw">
  <div class="diagram-col">
    <div class="diagram-node">Browser / UI</div>
    <div class="diagram-node">Agent loop</div>
    <div class="diagram-node">
      External clients<br /><small class="diagram-muted"
        >HTTP · MCP · A2A</small
      >
    </div>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&rarr;</div>
  <div class="diagram-panel" data-rough>
    <strong>Middleware</strong>
    <small class="diagram-muted">server/middleware/</small>
    <small class="diagram-muted">runs on every request</small>
  </div>
  <div class="mw-outcomes">
    <div class="mw-outcome">
      <span class="mw-label diagram-muted">allowed</span>
      <span class="mw-arrow diagram-muted" aria-hidden="true">&rarr;</span>
      <div class="diagram-box" data-rough>Routes &amp; handlers</div>
    </div>
    <div class="mw-outcome">
      <span class="mw-label diagram-muted">blocked</span>
      <span class="mw-arrow diagram-muted" aria-hidden="true">&rarr;</span>
      <div class="diagram-box" data-rough>Redirect / error</div>
    </div>
  </div>
</div>
```

```css
.diagram-mw {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.diagram-mw .diagram-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.diagram-mw .diagram-panel {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
}
.diagram-mw .diagram-arrow {
  font-size: 22px;
  line-height: 1;
}
.mw-outcomes {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.mw-outcome {
  display: flex;
  align-items: center;
  gap: 8px;
}
.mw-label {
  font-size: 11px;
  min-width: 44px;
  text-align: right;
}
.mw-arrow {
  font-size: 16px;
  line-height: 1;
}
```

</Diagram>

Files in `server/middleware/` are picked up automatically by Nitro — no registration required. Every file in that directory runs for every request, in alphabetical order.

## Writing Middleware {#writing-middleware}

A middleware file exports a `defineEventHandler`. To let the request continue, return nothing. To block it, throw a `createError` or return a redirect with `sendRedirect`.

```ts filename="server/middleware/cors.ts"
import { defineEventHandler, setResponseHeader } from "h3";

export default defineEventHandler((event) => {
  setResponseHeader(event, "Access-Control-Allow-Origin", "*");
  // returning nothing passes the request through to the route handler
});
```

Multiple middleware files run in alphabetical filename order before the matched route handler. Each middleware can inspect or modify the request, set response headers, or short-circuit the response entirely.

For more middleware patterns — conditional logic, async operations, response interception — see the [Nitro middleware docs](https://nitro.build/guide/routing#middleware) and the [H3 docs](https://h3.unjs.io).

## The Auth Middleware {#auth-middleware}

Every agent-native app ships `server/middleware/auth.ts`. It enforces authentication across all routes, including public page routes and custom `/api/*` routes that would otherwise bypass the framework's built-in auth.

### The Auth Guard {#auth-guard}

```ts filename="server/middleware/auth.ts"
import { runAuthGuard } from "@agent-native/core/server";
import { defineEventHandler } from "h3";

export default defineEventHandler(async (event) => {
  return runAuthGuard(event);
});
```

`runAuthGuard` checks every request against the auth configuration set up by the [auth plugin](/docs/server-plugins#auth-plugin). If the request is unauthenticated and the path is not in `publicPaths`, it redirects to the sign-in page.

### Why Middleware, Not a Plugin or Route Guard {#why-middleware}

The framework handler's built-in middleware registry is scoped to `/_agent-native/*` routes. Without a separate middleware file, page routes (`/`, `/settings`) and custom API routes (`/api/*`) bypass authentication entirely.

Plugins run at startup, not per-request, so they cannot enforce per-request auth. A route-level guard in each custom route handler is error-prone and easy to forget. Middleware in `server/middleware/` is the one place that runs for every request regardless of path.

### Adding Public Paths {#public-paths}

To allow unauthenticated access to specific paths, pass them to `createAuthPlugin` in `server/plugins/auth.ts` — not to the middleware directly:

```ts filename="server/plugins/auth.ts"
import { createAuthPlugin } from "@agent-native/core/server";

export default createAuthPlugin({
  publicPaths: ["/public", "/api/webhooks/stripe"],
  marketing: { appName: "My App", tagline: "..." },
});
```

`runAuthGuard` reads the configured public paths from the auth plugin at request time.

## What's next {#whats-next}

- [**Plugins**](/docs/server-plugins): auth plugin configuration that the middleware enforces
- [**Routes**](/docs/server-routes): custom routes that are protected by this middleware
- [**Security**](/docs/security): data scoping, access guards, and the full auth model
- [**Nitro middleware docs**](https://nitro.build/guide/routing#middleware): full middleware API and patterns
