# Setup Web Middleware

> >

- **Type:** Skill
- **Install:** `agentstack add skill-nexadevapp-nexa-claude-skills-marketplace-setup-web-middleware`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [nexadevapp](https://agentstack.voostack.com/s/nexadevapp)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [nexadevapp](https://github.com/nexadevapp)
- **Source:** https://github.com/nexadevapp/nexa-claude-skills-marketplace/tree/main/nexa-claude-nextjs/skills/setup-web-middleware

## Install

```sh
agentstack add skill-nexadevapp-nexa-claude-skills-marketplace-setup-web-middleware
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Build Web Middleware

## Instructions

Build the Next.js request interception and cross-cutting infrastructure for the project.
This skill produces the infrastructure that use case implementations depend on:
authentication, authorization, security headers, structured error logging, and server
error tracking.

Run this skill **after** the entity model and Prisma migration exist (so user/role entities
are available) and **before** implementing use cases.

## Step 0: Consult Next.js Documentation

**Before writing any code**, use the context7 MCP server to look up the current Next.js
documentation for the project's installed version (read `package.json` to determine the
version). Query for:

1. **Request interception file convention** — the correct file name, export name, runtime,
   and configuration format for the request interception entry point (historically
   `middleware.ts`, but this may change across versions)
2. **Runtime constraints** — which runtime the request interception layer runs in and what
   APIs are available or restricted (e.g. Edge Runtime vs Node.js, Prisma availability,
   native module support)
3. **Instrumentation and error tracking** — the correct file convention and exports for
   global server error tracking (e.g. `instrumentation.ts` with `onRequestError`)
4. **Matcher/config format** — how to configure which routes the interception layer applies to

Store these findings and use them throughout the remaining steps. Every file name, export
name, runtime constraint, and API choice in the steps below must align with what the
documentation says for the installed version — not with hardcoded assumptions.

## DO NOT

- Overwrite an existing request interception file without showing the user what will change and asking for confirmation
- Hard-code secrets, tokens, or credentials (use environment variables)
- Install authentication libraries without user confirmation (e.g. next-auth, lucia, clerk) — ask the user which auth approach to use
- Use libraries incompatible with the runtime determined in Step 0
- Import Prisma Client from the request interception entry point if the runtime does not support it
- Add i18n routing unless the requirements explicitly mention internationalization
- Add rate limiting logic inside the request interception layer (use a dedicated service or external provider)
- Create feature-specific logic in the interception layer — keep it generic and cross-cutting
- Skip reading the entity model — the layer must align with the project's user/role structure
- Set security headers in both the interception entry point and `next.config.js` — pick one location to avoid duplication and conflicts
- Hardcode file names or runtime constraints without checking the documentation first

## Nexa Rules Gate

Read and follow `${CLAUDE_PLUGIN_ROOT}/shared/readiness/NEXA_RULES_GATE.md`.

## Prerequisites

The following must exist before running this skill:

- `docs/requirements.md` (from `/requirements`) — to identify security and auth NFRs
- `docs/entity_model.md` (from `/entity-model`) — to understand user/role entities
- `prisma/schema.prisma` (from `/prisma-migration`) — to confirm user/role models exist

If any prerequisite is missing, stop and tell the user which `/command` to run first.

## Workflow

### Step 1: Gather Context

1. Read `docs/requirements.md` and extract:
   - Authentication requirements (login, session management, token type)
   - Authorization requirements (roles, permissions, RBAC rules)
   - Security NFRs (CSRF, headers, HTTPS enforcement)
   - Any explicit middleware-related requirements
2. Read `docs/entity_model.md` and identify:
   - The User entity (or equivalent) and its fields
   - Role/Permission entities and their relationship to User
   - Session or Token entities if defined
3. Read `prisma/schema.prisma` and verify the user/role models exist
4. Read `package.json` and check for existing auth libraries (`next-auth`, `lucia`, `@clerk/nextjs`, `@supabase/ssr`, etc.)

### Step 2: Retrofit Detection

Check whether the project already has implemented features by scanning for existing pages,
API routes, and server actions. This step determines whether the skill runs in **greenfield
mode** (no existing features) or **retrofit mode** (existing code that will be affected).

#### 2a. Scan for Existing Code

Search the codebase for:

- **Pages** — `app/**/page.tsx` files (excluding `app/page.tsx` if it's just a landing page)
- **API routes** — `app/api/**/route.ts` files
- **Server actions** — files containing `"use server"` in `app/actions/` or colocated with pages
- **Existing request interception** — check if a request interception file already exists at the project root (use the file name determined in Step 0)
- **Ad-hoc auth checks** — grep for patterns like `getServerSession`, `getSession`, `auth()`, `cookies().get`, `headers().get('authorization')`, or manual token validation in existing code

#### 2b. If Existing Request Interception Found

If a request interception file already exists, show the user its current content and ask:

> **An existing request interception file was found. Choose how to proceed:**
>
> 1. **Extend** — keep existing logic and add auth/security layers around it
> 2. **Replace** — discard the current file and build from scratch
> 3. **Abort** — stop and let me review the existing file first

Wait for the user to choose before proceeding.

#### 2c. If Existing Features Found (Retrofit Mode)

If pages, API routes, or server actions exist, activate **retrofit mode**.

**Impact analysis** — for each route protection rule (from Step 3), map it against the
existing routes and classify each file:

| File                        | Current Auth | Will Become     | Impact     |
|-----------------------------|-------------|-----------------|------------|
| `app/dashboard/page.tsx`    | None        | Authenticated   | **Breaking** — will redirect to login |
| `app/api/users/route.ts`   | Manual check | Authenticated  | Review — has ad-hoc auth, may conflict |
| `app/api/health/route.ts`  | None        | Authenticated   | **Breaking** — health check will require auth |
| `app/about/page.tsx`       | None        | Public          | No impact  |

Present this table to the user and ask:

> **Retrofit impact analysis:**
>
> The following existing routes will be affected:
>
> [impact table]
>
> **Breaking changes** require updates — these routes currently work without auth
> and will start redirecting or returning 403 after the interception layer is applied.
>
> **Review items** have existing ad-hoc auth that may conflict or duplicate the
> new logic.
>
> Options:
> 1. **Proceed** — I'll adjust the route protection rules to minimize breakage and
>    generate a migration checklist for the remaining changes
> 2. **Adjust rules** — let me customize which routes stay public before proceeding
> 3. **Abort** — let me review the existing code first

Wait for the user to choose before proceeding.

#### 2d. Ad-hoc Auth Consolidation Plan

If existing code contains ad-hoc auth checks (from 2a), list each file and its current
auth pattern:

> **Existing ad-hoc auth found in these files:**
>
> | File                       | Current Pattern                          | Recommendation          |
> |----------------------------|------------------------------------------|-------------------------|
> | `app/api/users/route.ts`   | `getServerSession()` + manual role check | Remove — interception layer handles it |
> | `app/actions/create-post.ts` | `auth()` guard at top of action        | Keep — server actions need explicit auth since the interception layer only covers the request |
> | `app/dashboard/page.tsx`   | `redirect()` if no session               | Remove — interception layer redirects |
>
> After the interception layer is built, I will update these files as part of the migration checklist.

**Important:** Server actions called via `fetch` or form submission go through the
interception layer, but server actions called directly from server components do not.
For these, the explicit auth check in the action itself must be **kept**, not removed.
Flag this distinction clearly in the consolidation plan.

#### 2e. Generate Migration Checklist

If in retrofit mode, create a technical task following the standard `TT-XXX` naming convention:

1. Read existing files in `docs/technical_tasks/` to determine the next available `TT-XXX` ID (zero-padded, 3 digits — e.g. if `TT-003.md` is the highest, the next is `TT-004`)
2. Create `docs/technical_tasks/TT-XXX-middleware-retrofit.md` using the template from `nexa-claude-core/skills/technical-task/templates/technical-task.md` with:
   - **Task ID:** `TT-XXX` (the assigned numeric ID)
   - **Task Name:** Middleware Retrofit — Consolidate Ad-hoc Auth
   - **Category:** Cleanup
   - **Goal:** Adapt existing routes and server actions to use the new auth layer, removing redundant ad-hoc auth checks and updating tests
   - **Status:** Approved
   - **Acceptance Criteria:** one checklist item per file that needs updating, grouped by change type:
     - **Remove redundant auth** — files where the interception layer now handles what the code did manually
     - **Keep explicit auth** — server actions that need their own auth check
     - **Update tests** — test files that need auth tokens/sessions added to their setup
     - **Review conflicts** — files with auth logic that may conflict with the new behavior
   - **Affected Areas:** every file identified in the retrofit analysis
   - **Dependencies:** None

This checklist becomes the work plan for adapting existing code after the interception layer is in place.

**Do not apply the migration changes in this skill.** The checklist is implemented via
`/implement TT-XXX-middleware-retrofit` (using the assigned ID) as a follow-up step, so each
change can be reviewed individually.

### Step 3: Confirm Auth Strategy with User

If an auth library is already installed in `package.json`, lead with it:

> **I found `` in your dependencies. Should I build the interception layer around it?**
>
> If not, choose an alternative:

If no auth library is installed, present options. Use the context7 MCP server to check
which auth libraries are compatible with the runtime determined in Step 0, then present:

> **Authentication strategy — choose one:**
>
> [list options compatible with the runtime, e.g. session-based, JWT, external provider]

Wait for the user to choose before proceeding.

### Step 4: Define Route Protection Rules

Ask the user to confirm or adjust the default route protection rules:

> **Route protection rules (adjust as needed):**
>
> | Pattern             | Rule           |
> |---------------------|----------------|
> | `/`                 | Public         |
> | `/login`, `/signup` | Public (redirect if authenticated) |
> | `/api/auth/**`      | Public         |
> | `/dashboard/**`     | Authenticated  |
> | `/admin/**`         | Authenticated + Admin role |
> | `/api/**`           | Authenticated  |
>
> Should I proceed with these defaults, or do you want to customize them?

Incorporate the user's adjustments.

### Step 5: Build the Infrastructure

Create the files below. For every file, use the conventions determined in Step 0 (file
names, export names, runtime APIs, matcher format). Consult the context7 MCP server again
if you need to clarify any API or convention.

#### 5a. Request Interception Entry Point (project root)

Create the entry point file using the correct file name and export name from Step 0. It must:

- Export the entry function and configuration using the convention from the docs
- Use the matcher/config to exclude static assets and internal Next.js routes
- Wrap the entire function body in a try/catch. On unexpected errors, log the error with full context and **fail closed** (redirect to login rather than letting the request through)
- Follow this composition pattern:
  1. Check if the route is public — if so, log at debug level, apply security headers and return
  2. Validate the session/token (respect runtime constraints — if DB calls are not available, validate statelessly)
  3. If unauthenticated on a protected route — log a warning with the path and redirect to login
  4. If authenticated on an auth route (login/signup) — log at debug level and redirect to dashboard
  5. If route requires a specific role and user lacks it — log a warning with the path, user ID, and required vs. actual roles, then return 403 or redirect
  6. Apply security headers to the response
  7. Return the response

#### 5b. `lib/auth/middleware.ts`

Auth-specific helpers (must respect the runtime constraints from Step 0):

- `getSessionFromRequest(request)` — extract and validate the session/token from the request cookie or Authorization header. Use libraries compatible with the runtime. Must never throw — catch verification errors internally, log them, and return `null`
- `isAuthenticated(session)` — check if the session is valid and not expired
- `hasRole(session, role)` — check if the user has the required role

#### 5c. `lib/auth/constants.ts`

Route and auth constants:

- `PUBLIC_ROUTES` — array of public route patterns
- `AUTH_ROUTES` — array of auth-related routes (login, signup) that redirect when authenticated
- `ROLE_PROTECTED_ROUTES` — map of route patterns to required roles, supporting multiple roles per route
- `DEFAULT_LOGIN_REDIRECT` — where to redirect after login (e.g. `/dashboard`)
- `LOGIN_PAGE` — the login page path

#### 5d. `lib/auth/headers.ts`

Security headers utility. Set headers **only** in the interception entry point — not in
`next.config.js` — to avoid duplication and conflicts:

- `securityHeaders()` — returns a `Headers` object with:
  - `Content-Security-Policy` — start with a restrictive baseline and add a comment noting it should be tuned per project
  - `X-Frame-Options: DENY`
  - `X-Content-Type-Options: nosniff`
  - `Referrer-Policy: strict-origin-when-cross-origin`
  - `X-DNS-Prefetch-Control: off`
  - `Permissions-Policy` with sensible defaults (e.g. `camera=(), microphone=(), geolocation=()`)
  - `Strict-Transport-Security: max-age=31536000; includeSubDomains` (production only — check `process.env.NODE_ENV`)

#### 5e. `lib/auth/logger.ts`

Structured logger (must respect the runtime constraints from Step 0 — use only APIs
available in the determined runtime):

- Create a logger object with `debug`, `warn`, and `error` methods
- Every log message must be a **structured JSON string** with these fields:
  - `timestamp` — ISO 8601
  - `level` — `DEBUG`, `WARN`, or `ERROR`
  - `source` — identifies this as the request interception layer
  - `path` — the request path
  - `method` — the HTTP method
  - `message` — human-readable description of what happened
  - Additional context fields depending on the event (see below)
- `debug` level is only emitted when `process.env.NODE_ENV !== 'production'` to avoid noise
- Define explicit log messages for each decision point:

| Event                     | Level   | Additional Fields                                      |
|---------------------------|---------|--------------------------------------------------------|
| Public route — allowed    | `DEBUG` | —                                                      |
| Auth route — redirected   | `DEBUG` | `userId`, `redirectTo`                                 |
| Token missing             | `WARN`  | `redirectTo`                                           |
| Token expired             | `WARN`  | `userId` (if decodable), `expiredAt`                   |
| Token malformed           | `WARN`  | `error` (the parse error message, not the token value) |
| Token signature invalid   | `ERROR` | `error`                                                |
| AUTH_SECRET missing       | `ERROR` | —                                                      |
| Role check failed         | `WARN`  | `userId`, `requiredRoles`, `actualRoles`, `redirectTo` |
| Unexpected error

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [nexadevapp](https://github.com/nexadevapp)
- **Source:** [nexadevapp/nexa-claude-skills-marketplace](https://github.com/nexadevapp/nexa-claude-skills-marketplace)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-nexadevapp-nexa-claude-skills-marketplace-setup-web-middleware
- Seller: https://agentstack.voostack.com/s/nexadevapp
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
