Welcome back. At this point, your Task Manager API can:
- Represent tasks with a shared
Taskmodel and in-memory store - Manipulate them through a clean service layer
- Validate incoming payloads and surface clear errors through HTTP
That’s a solid backend—but right now it’s wide open to anyone who can hit your endpoints, and you have very little visibility into who’s calling what.
In this lesson, you’ll use Codex to:
- Configure a secret API key in environment variables
- Add a middleware that enforces that key on
/api/tasksand logs every request - Build a Task Manager API testing panel in
src/app/page.tsxthat sends the right headers and lets you exercise all CRUD endpoints from the browser
By the end, you’ll have a Task Manager backend with a simple but real security gate and a handy UI “cockpit” for manual testing.
This lesson introduces two important backend concepts:
-
Configuration via environment variables
- Secrets (like API keys) never belong in source code.
- Using
.env.locallets you swap configuration per environment without changing code.
-
Cross-cutting middleware for security and logging
- Instead of securing each route individually, you add a single gate that runs before all
/api/taskshandlers. - The same middleware can also log the who/what/when of every request.
- Instead of securing each route individually, you add a single gate that runs before all
On top of that, you’ll wire a simple UI panel that:
- Lets you type an API key
- Sends that key in the
x-api-keyheader on all requests - Provides controls to call every task endpoint
- Shows a live log of responses and client-side errors
This combination gives you both a lock on the API and a dashboard to test it.
Codex will help you in three small, focused bursts:
-
Environment setup
- Edit
.env.localto defineSECRET_API_KEY=...
- Edit
-
Middleware implementation
- Fill in
src/middleware.tswith:- Path matching for
/api/tasks - API key checks
- Structured console logging
- Path matching for
- Fill in
-
UI testing panel
- Extend
src/app/page.tsxinto a control panel that:- Manages state for API key and task fields
- Sends
x-api-keyin everyfetch - Logs results in a “Logs” section
- Extend
Your prompts should continue to follow the pattern you’ve been practicing:
- “Modify only
<file>.” - Describe the exact behavior in detail.
- Explain any important security or logging rules.
- “Do not modify any other files. Show the full updated contents of
<file>.”
First, you’ll define the secret your middleware will use. The project already includes a placeholder .env.local file with guidance (as shown above).
Your job (with Codex’s help) is to turn this into a real configuration entry, for example:
SECRET_API_KEY=my-secret-task-api-key
Key points:
.env.locallives at the project root.- It should not be checked into public version control in real-world projects.
- Your code accesses this value through
process.env.SECRET_API_KEY, never by hard-coding the key.
A typical Codex prompt here is very small and very strict:
Codex, modify only
.env.local.Add a line defining
SECRET_API_KEYwith a non-empty placeholder value (for example,my-secret-task-api-key) that will be used to protect/api/tasks.Do not modify any other files. Show the full updated
.env.localfile.
Once this is set, your middleware can start enforcing it.
Next, you’ll implement security and logging logic in src/middleware.ts. The starter file already sketches the structure (as shown in the snippet).
You’ll ask Codex to complete this so that the middleware:
-
Runs for all
/api/*routes- The
config.matcheris already set to'/api/:path*'.
- The
-
Enforces the API key on
/api/tasksroutes- Reads the header:
const apiKey = request.headers.get('x-api-key');
- Compares it to
process.env.SECRET_API_KEY. - If missing or incorrect, returns a 401 JSON response, for example:
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
- Reads the header:
-
Logs each request with structured metadata
- For example:
timestamp: new Date().toISOString()method: request.methodpath
- For example:
Now that /api/tasks is locked behind an API key, hitting it from the browser becomes more interesting. Instead of reaching for an external client, you’ll build a tiny testing panel inside src/app/page.tsx.
The starter file already includes a basic structure (shown above). You’ll ask Codex to evolve this page into a simple “mini Postman” that can:
-
Manage state for:
apiKeytaskIdtitlecontentdueDate- A JSON string for PUT/PATCH payloads
-
Render inputs and buttons for:
GET /api/tasksGET /api/tasks/{id}POST /api/tasksPUT /api/tasks/{id}PATCH /api/tasks/{id}DELETE /api/tasks/{id}
-
Include the
x-api-keyheader in every fetch, for example:
In this lesson, you:
- Defined a secret API key in
.env.localso sensitive configuration lives outside your code. - Implemented security + logging middleware in
src/middleware.tsthat:- Protects
/api/taskswith anx-api-keycheck - Logs structured metadata for every API request
- Protects
- Turned
src/app/page.tsxinto a Task Manager API testing panel that:- Sends the API key in headers
- Exercises all CRUD routes
- Shows logs for each interaction
You now have a Task Manager backend that’s not only structured and validated, but also gated and observable, plus a built-in UI to experiment with it.
From here, future courses can build on this foundation by adding more advanced concerns—like more sophisticated auth, better logging destinations, or persistent storage—while still using the same Codex-driven workflow you’ve been practicing.
