---
title: "Lock the Doors"
description: "Make the dispatcher production-safe: understand the fail-closed auth guarantee, keep the model credential and secrets in env, and confirm an unknown caller gets shut out."
canonical_url: "https://vercel.com/academy/building-agents-with-eve/lock-the-doors"
md_url: "https://vercel.com/academy/building-agents-with-eve/lock-the-doors.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-06-30T17:26:22.036Z"
content_type: "lesson"
course: "building-agents-with-eve"
course_title: "Building Agents with eve"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Lock the Doors

# Lock the Doors

The dispatcher is about to stop being a thing on your laptop and start being a thing on the internet. The internet is full of people who are not your customers, and a few who'd love to book a thousand overhauls or read someone else's garage. Before we deploy, we make sure the only people who can reach the agent are the ones who should.

The good news: you did most of this in 4.3. The auth walk you wrote already decides who gets in. What's left is to understand what happens to everyone it doesn't recognize, confirm it's the right thing, and make sure no secret rides along in your source code.

## Outcome

You can state exactly what an unauthenticated request to the deployed dispatcher gets, and your model credential and any secrets live in environment variables, not in the repo.

## Hands-on exercise

**Understand fail-closed.** Your `auth` list is `[appAuth, localDev(), vercelOidc()]`. Walk through what each does to a *public production* request from a stranger's browser:

- `appAuth` calls `getCustomer` and finds no valid session → returns `null`, falls through.
- `localDev()` only accepts requests to a loopback hostname (`localhost`, `127.0.0.1`). A public request isn't loopback → falls through.
- `vercelOidc()` wants a valid Vercel OIDC token the stranger doesn't have → falls through.

Every entry falls through, so eve returns a `401`. That's the fail-closed guarantee: routes reject anything no authenticator explicitly accepted. You don't switch on a "secure mode", unrecognized traffic is denied by default.

\*\*Warning: Why localDev() is safe to leave in production\*\*

It's tempting to think shipping `localDev()` opens a hole. It doesn't, it keys off the request's *hostname*, not an env flag, and a public request never arrives on a loopback host. It keeps your local dev and same-origin dashboard working without admitting a single outside caller. (One caveat from the docs: put a normalizing proxy in front of your origin so a forged `Host` header can't spoof loopback.)

\*\*Note: The scaffold ships placeholderAuth() for this reason\*\*

A fresh eve project doesn't start wide open, it starts with `placeholderAuth()` in the walk, which returns a clear "auth isn't configured yet" `401` in production. It's a guardrail so a half-built app fails closed instead of leaking. You replaced it with real auth back in 4.3; this is the behavior it was holding the place for.

**Keep secrets in env.** The dispatcher needs exactly one credential to run: a model key. The easy, secret-free path is the Vercel AI Gateway, link a Vercel project and a gateway id like `anthropic/claude-opus-4.8` authenticates through OIDC, with no provider key to store anywhere:

```bash
npx eve link   # links this directory to a Vercel project and pulls Gateway creds
```

Anything sensitive your real `getCustomer` would use (a session-signing secret, a JWT key) belongs in Vercel's environment variables, never in source. Route-auth secrets are re-materialized from env at boot and never baked into the build artifacts.

## Try It

Confirm the lock from the outside. With the agent running, send a request that looks like an unauthenticated outsider, no session cookie, no OIDC token, addressed as if from off-box:

```bash
curl -i -X POST http://127.0.0.1:2000/eve/v1/session \
  -H 'content-type: application/json' \
  -H 'host: dispatcher.example.com' \
  -d '{"message":"hello"}'
```

```text
HTTP/1.1 401 Unauthorized
{ "ok": false, "code": "unauthorized" }
```

Now confirm a real customer still gets in, the `demo-pro` session from 4.3 works:

```bash
curl -i -X POST http://127.0.0.1:2000/eve/v1/session \
  -H 'content-type: application/json' -H 'cookie: shop_session=demo-pro' \
  -d '{"message":"hello"}'
```

```text
HTTP/1.1 200 OK
{ "sessionId": "...", "continuationToken": "..." }
```

Stranger out, customer in. That's the door working. Finally, sweep for secrets you don't want in git:

```bash
git grep -nE "sk-|api[_-]?key|secret" -- . ':!*.lock' || echo "clean"
```

\*\*Note: Production-safe is mostly verifying, not adding\*\*

Notice you barely wrote code here. eve's defaults, fail-closed routes, secrets re-materialized from env, OIDC model auth, do the heavy lifting. "Hardening for production" is largely confirming the framework's safe defaults are still in force and that you didn't paste a key somewhere.

If the `demo-pro` request also gets a `401`, your `appAuth` isn't first in the walk, or `getCustomer` isn't reading the cookie. If you can't reach a model after linking, run `eve link` again and confirm the project has AI Gateway access.

## Done-When

- [ ] An unauthenticated, non-loopback request returns `401`.
- [ ] A valid customer session still returns `200` with a session.
- [ ] The model credential comes from a linked Vercel project / env, not source.
- [ ] `git grep` for secrets comes back clean.

## Solution

There's no new file here, the "solution" is the auth walk you already wrote in 4.3, now understood as a production lock:

```ts title="agent/channels/eve.ts (unchanged from 4.3)"
export default eveChannel({
  auth: [appAuth, localDev(), vercelOidc()],
});
```

`appAuth` lets your customers in. `localDev()` and `vercelOidc()` cover loopback and internal Vercel traffic. Everything else hits the fail-closed `401`. With the door confirmed and the model credential in env, there's nothing risky left to do but the satisfying part, putting it on the internet.


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
