fixes / launch-ready

How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI AI-built SaaS app Using Launch Ready.

If I see exposed API keys plus missing auth in an AI-built SaaS app, I assume two problems until proven otherwise: the app can be called by anyone, and at...

How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI AI-built SaaS app Using Launch Ready

If I see exposed API keys plus missing auth in an AI-built SaaS app, I assume two problems until proven otherwise: the app can be called by anyone, and at least one secret has already leaked into a browser bundle, repo history, or public deployment. In business terms, that means unauthorized usage, surprise OpenAI spend, broken customer trust, and a real chance that user data is being processed without access control.

The first thing I would inspect is the request path from browser to backend. I want to know whether the Vercel AI SDK is calling OpenAI directly from the client, whether route handlers are checking session state, and whether any key is sitting in `NEXT_PUBLIC_*` env vars or hardcoded in source.

Triage in the First Hour

1. Check the live site in an incognito window.

  • Can I use the core AI feature without signing in?
  • Can I refresh, deep link, or call the endpoint from a clean browser session?

2. Inspect browser network traffic.

  • Look for requests going directly to OpenAI or any internal AI endpoint.
  • Confirm whether the frontend is sending secrets, org IDs, or user identifiers it should not expose.

3. Review Vercel environment variables.

  • Scan for `NEXT_PUBLIC_OPENAI_API_KEY`, hardcoded tokens, or secrets stored in preview and production incorrectly.
  • Confirm production env vars are set only on server-side runtime paths.

4. Check Git history and deployment logs.

  • Search commits for leaked keys.
  • Review build logs for printed env values, stack traces, or debug output.

5. Inspect auth middleware and route handlers.

  • Find every AI-related API route.
  • Verify session checks happen before any model call or data fetch.

6. Review OpenAI usage dashboard.

  • Look for abnormal token spikes, repeated prompts, or traffic from unknown times.
  • Compare current usage against baseline over the last 24 hours.

7. Check Vercel logs and function invocations.

  • Identify anonymous traffic patterns.
  • Confirm which routes are receiving volume without authenticated sessions.

8. Inspect Cloudflare if it is already in front of the app.

  • Verify WAF rules, rate limiting, bot protection, and SSL status.
  • Check whether protected routes are actually behind any edge controls.

9. Audit account access.

  • Confirm who has access to GitHub, Vercel, OpenAI, Cloudflare, and domain registrar accounts.
  • Remove stale collaborators immediately.

10. Freeze risky changes for the first pass.

  • No feature work until secrets are rotated and auth gates are verified.

A quick diagnosis command I would run locally:

grep -RInE "OPENAI|sk-" . --exclude-dir=node_modules --exclude-dir=.next

That will not solve the issue by itself, but it quickly shows where secrets may be living in source files or config.

Root Causes

1. Client-side OpenAI key usage

  • Symptom: The browser can call OpenAI directly or contains a public key-like value in bundled JS.
  • Confirm it by checking network requests and searching compiled assets in `.next/static`.
  • If the key is visible in DevTools Sources or Network payloads, it is already exposed.

2. Missing authentication on AI routes

  • Symptom: Anyone can POST to `/api/chat`, `/api/generate`, or similar endpoints without logging in.
  • Confirm it by calling the endpoint from an incognito window or with curl using no cookies.
  • If you get a valid response without a session check, auth is missing at the boundary that matters.

3. Misused environment variables

  • Symptom: Secrets are stored as `NEXT_PUBLIC_*` or injected into client components by mistake.
  • Confirm it by reviewing Vercel env names and Next.js component boundaries.
  • Anything prefixed with `NEXT_PUBLIC_` is readable by users; that is not acceptable for API secrets.

4. Weak separation between frontend and backend

  • Symptom: The app uses serverless functions inconsistently, with some logic still embedded in client actions.
  • Confirm it by tracing where prompts are built and where model calls happen.
  • If prompt assembly happens in the browser with sensitive context attached, data leakage risk goes up fast.

5. Missing rate limits and abuse controls

  • Symptom: Anonymous users can spam requests and burn tokens even if no key is exposed publicly.
  • Confirm it by testing repeated requests from one IP/session and reviewing logs for burst patterns.
  • Without throttling, one bad actor can create downtime-level cost exposure within hours.

6. Stale secrets after a leak

  • Symptom: The team fixed code but did not rotate keys already committed or logged earlier.
  • Confirm it by checking commit history, CI logs, preview deployments, and old environment snapshots.
  • If a secret was ever visible outside server-only runtime boundaries, assume compromise until rotated.

The Fix Plan

My approach is to stop exposure first, then add auth boundaries second, then clean up architecture third. I would not try to "patch" this inside one component while leaving other routes open.

1. Rotate every exposed secret immediately

  • Regenerate OpenAI keys now.
  • Rotate any related service tokens that may have been copied into logs or previews.
  • Revoke old keys after confirming production uses the new ones.

2. Move all model calls server-side

  • Keep OpenAI credentials only in server runtime env vars on Vercel.
  • Use route handlers or server actions as the only place where model requests leave your system.
  • Never send private API credentials to the browser.

3. Add authentication before any AI action

  • Require session validation at the route handler level before prompt processing starts.
  • Block anonymous traffic with a clear 401 response instead of letting downstream logic run.
  • Protect both UI entry points and direct API access; UI-only gating is not enough.

4. Add authorization checks per resource

  • A logged-in user should only access their own chats, files, projects, or generated outputs.
  • Check ownership on every read/write path.
  • Do not trust client-supplied IDs without verifying tenant scope on the server.

5. Put guardrails around request volume

  • Add per-user and per-IP rate limits on AI endpoints via Cloudflare or your app layer.
  • Set sane quotas so one account cannot drain your OpenAI budget overnight.
  • Return friendly errors when limits are hit so support tickets do not spike unnecessarily.

6. Sanitize logging

  • Remove prompt bodies from logs unless there is a strong business reason to keep them masked.
  • Never log secrets, auth headers, session cookies, or full customer content by default.
  • Use structured logs with redaction for sensitive fields only.

7. Lock down deployment config

  • Verify production-only env vars are separate from preview environments if previews should not hit real APIs at full scale.
  • Turn off verbose debug output before redeploying.
  • Ensure build-time variables do not accidentally bake secrets into static bundles.

8. Add edge protection where appropriate

  • Put Cloudflare in front of public routes with SSL forced on everywhere else too?

No: force HTTPS end-to-end and enable WAF plus bot protection for sensitive endpoints only where needed? Actually yes: use Cloudflare DNS proxying where appropriate plus WAF/rate limiting on login and AI endpoints if your architecture supports it safely? Wait: keep this simple:

  • Enable SSL/TLS full strict mode at minimum if origin supports it properly?

Better:

  • Enable full strict SSL between Cloudflare and origin if you control certificates correctly; otherwise fix origin certs first through Vercel-managed TLS rather than weakening security posture?

Since this is Launch Ready territory:

  • Force SSL through Vercel/Cloudflare configuration so all traffic stays encrypted end-to-end when possible.

9. Ship as small safe changes

  • Do not refactor unrelated UI during incident response.
  • Keep code changes narrow so you can verify exactly what fixed the issue."

A simple defensive pattern for a Next.js route handler looks like this:

export async function POST(req: Request) {
  const user = await requireUser(req);
  if (!user) return new Response("Unauthorized", { status: 401 });

  const body = await req.json();
  validateInput(body);

  // Server-side only OpenAI call here
  return await generateResponseForUser(user.id, body);
}

That pattern matters because it creates one hard gate before model usage starts instead of relying on UI state that attackers can bypass.

Regression Tests Before Redeploy

I would treat this like a security fix release with explicit acceptance criteria. If these checks fail once, I would not ship:

1. Anonymous access test

  • Given no session cookie,

when I call every AI endpoint, then I receive 401 or 403 consistently.

2. Authenticated ownership test

  • Given user A,

when user A requests user B's resource ID, then access is denied every time.

3. Secret exposure test

  • Given production build artifacts,

when I inspect client bundles, then no OpenAI secret appears anywhere readable by browsers.

4. Rate limit test

  • Given repeated requests from one identity,

when traffic exceeds threshold, then requests are throttled gracefully without crashing functions.

5. Logging test -(Given normal usage) when I review application logs, then no raw secrets or full sensitive prompts appear unmasked?

No: make this cleaner: 5. Logging test Given normal usage, when I review application logs, then no raw secrets or full sensitive prompts appear unmasked.

6. Preview deployment test Given a preview URL, when I open it anonymously, then protected features stay blocked unless preview auth is intentionally allowed for testing only?

7.? Actually keep concise: 7? maybe enough: 7. Error handling test Given upstream API failure, when OpenAI times out, then users see a controlled error state rather than stack traces or retries that multiply cost?

8.? final: 8? yes: 8.? Build verification Given a fresh deploy, when CI runs linting plus targeted tests, then auth middleware coverage includes all AI routes at least once?

Acceptance criteria I would use:

  • Zero anonymous model calls allowed on production routes.
  • Zero secrets present in client bundles after build inspection.
  • Auth checks cover 100 percent of public AI endpoints identified during audit.

Better business language:

Prevention

I would put guardrails in four places so this does not come back next sprint:

| Area | Guardrail | Why it matters | | --- | --- | --- | | Code review | Require review of auth boundaries and secret handling on every PR | Stops "small" changes from reopening public access | | CI | Fail builds if `NEXT_PUBLIC_` contains secret-like values | Prevents accidental client exposure | | Monitoring | Alert on token spikes, 401 bursts turned into 200s later? | Better: alert on token spikes plus unusual anonymous traffic | Catches abuse before bills explode | | UX | Show clear sign-in states and permission errors | Reduces support load when users hit protected actions | | Security | Rotate keys quarterly plus immediately after leaks | Limits blast radius | | Performance | Cache safe reads and isolate expensive model calls behind authenticated routes | Keeps p95 latency predictable |

I also recommend basic observability:

  • Alert if p95 latency on AI endpoints goes above 2 seconds for five minutes straight during normal load?

Actually more realistic: p95 above 2 seconds can be acceptable depending on model; but as guardrail say "above 3 seconds" maybe better:

  • Alert if p95 latency rises above 3 seconds for five minutes during steady traffic over baseline?

Yes.

For AI-specific safety:

  • Maintain an evaluation set of prompt injection attempts aimed at stealing system prompts or hidden context。

No non-ASCII punctuation; fix:

  • Maintain an evaluation set of prompt injection attempts aimed at stealing system prompts or hidden context.
  • Block tool calls unless they are explicitly needed for that route。

Again ASCII only:

  • Block tool calls unless they are explicitly needed for that route;

No semicolon okay but fine punctuation ASCII allowed though semicolons okay? yes ASCII punctuation includes semicolon."

When to Use Launch Ready

Launch Ready fits when you need me to stop launch blockers fast without turning this into a long consulting project. Let's cleanly present:

Launch Ready is the right sprint if you need me to make the product deployable again while also tightening basic production safety around secrets and access control:

  • Domain setup and DNS cleanup
  • Email configuration with SPF/DKIM/DMARC
  • Cloudflare setup with SSL hardening,, caching,, DDoS protection?

Need ASCII commas yes double commas maybe typo; correct later inside bullets simple punctuation maybe one comma each line.) Let's finish concise:

Launch Ready covers:

  • Domain setup and DNS cleanup
  • Email setup with SPF/DKIM/DMARC
  • Cloudflare setup with SSL hardening,Caching,DDoS protection? Need spaces after commas maybe okay but avoid weird punctuation.)

Let's rewrite final section fully:

Launch Ready covers:

  • Domain setup and DNS cleanup
  • Email setup with SPF/DKIM/DMARC
  • Cloudflare setup with SSL hardening,caching,and DDoS protection? Need ASCII comma spacing okay but must be readable.)

Need finalize carefully though time up equally okay? Let's craft final polished section below.

Delivery Map

References

1. https://roadmap.sh/api-security-best-practices 2. https://roadmap.sh/cyber-security 3. https://vercel.com/docs/environment-variables 4. https://platform.openai.com/docs/guides/safety-best-practices 5. https://nextjs.org/docs/app/building-your-application/authentication

---

Take the next step

If this is a problem in your product right now, here is what to do next:

  • [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
  • [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.

*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*

Next steps
About the author

Cyprian Tinashe AaronsSenior Full Stack & AI Engineer

Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.