How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI client portal Using Launch Ready.
The symptom is usually obvious: someone finds an OpenAI key in the browser bundle, a public repo, or a deployed preview URL, and the portal also lets...
How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI client portal Using Launch Ready
The symptom is usually obvious: someone finds an OpenAI key in the browser bundle, a public repo, or a deployed preview URL, and the portal also lets unauthenticated users hit expensive AI endpoints. The most likely root cause is the same in both cases: the app was built fast, but the security boundary was never drawn between the client portal and the server.
The first thing I would inspect is where the OpenAI call actually happens. If I see API keys in frontend code, Vercel env vars exposed to `NEXT_PUBLIC_` variables, or an AI SDK route that has no session check, I know this is a production risk, not just a code smell.
Triage in the First Hour
1. Check the live portal in a private browser window.
- Try every AI action without logging in.
- Confirm whether anonymous users can trigger chat, file upload, or report generation.
2. Inspect browser source and network traffic.
- Look for OpenAI keys, bearer tokens, or internal URLs in JS bundles.
- Check whether sensitive prompts or customer data are being sent from the client directly.
3. Review Vercel deployment settings.
- Confirm which environment variables are set for Production, Preview, and Development.
- Look for any secrets mistakenly prefixed with `NEXT_PUBLIC_`.
4. Check Git history and recent commits.
- Search for `.env`, `apiKey`, `OPENAI_API_KEY`, `Authorization`, and hardcoded secrets.
- Confirm whether a key was ever committed or pasted into a prompt file.
5. Review server logs and function logs.
- Look for unusual request volume, repeated 401s or 200s from anonymous traffic, and high token usage.
- Identify whether requests are coming from bots, previews, or unknown IP ranges.
6. Audit auth screens and session flow.
- Confirm login redirects work on desktop and mobile.
- Verify protected routes do not render data before auth finishes.
7. Check OpenAI account usage dashboard.
- Compare token spend over the last 24 hours with normal baseline.
- If spend spiked by more than 30 percent, assume abuse until proven otherwise.
8. Rotate any exposed secret immediately if it appeared in client code, logs, or repo history.
- Do this before deeper debugging if there is any doubt.
## Quick search for likely secret leaks git grep -n "OPENAI_API_KEY\|apiKey\|Authorization\|Bearer\|NEXT_PUBLIC_" .
Root Causes
| Likely cause | What it looks like | How I confirm it | |---|---|---| | API key used in client code | Key appears in browser bundle or React component | Search built assets and Network tab | | Missing route-level auth | Anonymous users can call `/api/*` endpoints | Hit endpoints from private window without login | | Misconfigured env vars | Secret stored as public variable on Vercel | Check Vercel env var names and scopes | | No server-side proxy layer | Frontend sends OpenAI requests directly | Inspect code for direct SDK calls in client components | | Weak session enforcement | UI hides content but backend still serves it | Call protected endpoints with no cookie/token | | Leaked secret in repo history | Old commit contains real key | Scan git log and rotate affected credentials |
The most common mistake is assuming UI protection equals backend protection. It does not. If the page shows a login gate but the API route accepts any request, your cost exposure and data exposure are still live.
Another common issue is using the Vercel AI SDK correctly on paper but placing the route handler inside logic that never checks identity. The model call should be behind authentication first, then authorization second, then rate limiting third.
The Fix Plan
1. Stop the bleed first.
- Rotate every exposed OpenAI key.
- Remove compromised secrets from Vercel immediately.
- Revoke any related tokens if they were stored alongside the key.
2. Move all model calls to server-only code.
- Keep OpenAI calls inside route handlers, server actions, or backend services only.
- Never ship provider secrets to client components or public environment variables.
3. Add authentication at the API boundary.
- Require a valid session before any AI request runs.
- Return `401` for unauthenticated users and `403` for authenticated users without access to that feature.
4. Add authorization by tenant or role.
- If this is a client portal, check that the user belongs to the right account before serving prompts or files.
- Do not rely on hidden UI tabs or disabled buttons as access control.
5. Add rate limits and abuse controls.
- Limit requests per user per minute and per org per day.
- Add request size caps so someone cannot dump huge payloads into your model endpoint.
6. Sanitize inputs before sending them to OpenAI.
- Strip secrets, internal IDs, payment data, and raw tokens from prompts where possible.
- Only send what is needed for the task.
7. Lock down environment variables on Vercel.
- Keep provider keys server-only.
- Use separate values for Preview vs Production if needed for safety testing.
8. Review CORS only if you truly need cross-origin access.
- For a client portal, default to same-origin requests where possible.
- Do not open permissive CORS just to make local testing easier.
9. Add audit logging without leaking sensitive data.
- Log user ID, org ID, endpoint name, timestamp, status code, latency, and token count if available.
- Do not log full prompts containing customer data or secrets.
10. Patch any direct frontend references to secret-bearing config.
- Replace them with backend-provided session-aware responses.
- Rebuild and redeploy after validation.
My preferred path is boring on purpose: one authenticated server route per AI capability, one clear permission check at entry, one rotated secret set, one deploy after tests pass. That reduces launch risk faster than trying to redesign everything at once.
Regression Tests Before Redeploy
I would not redeploy until these pass:
- Anonymous access test
- Open an incognito window and hit every AI endpoint directly.
- Expected result: `401 Unauthorized` with no model call made.
- Role-based access test
- Log in as a standard user who should not have admin features.
- Expected result: restricted features return `403 Forbidden`.
- Secret leakage test
- Search built JS bundles for OpenAI keys and private tokens.
- Expected result: none found.
- Rate limit test
- Send repeated valid requests from one account within 60 seconds.
- Expected result: requests beyond threshold are blocked gracefully.
- Error handling test
- Force upstream failures from OpenAI by using an invalid temporary config in staging only.
- Expected result: user sees a safe error message; stack traces stay server-side.
- Prompt safety test
- Submit content containing fake secrets or prompt injection text from uploaded files or chat input.
- Expected result: app does not echo secrets back into logs or downstream prompts unnecessarily.
- Session expiry test
- Let login expire and retry an AI action after refresh delay of 15 to 30 minutes depending on your auth setup.
- Expected result: user is redirected to sign-in cleanly.
Acceptance criteria I would use:
- Zero exposed secrets in frontend bundles or public repos after cleanup.
- Every AI endpoint requires auth before execution.
- p95 response time under 2 seconds for normal portal actions excluding model latency variance where applicable.
- No unauthorized successful requests across at least 20 manual checks plus automated coverage on protected routes.
Prevention
I would put guardrails around this so it does not happen again:
- Code review rules
- Block any PR that introduces provider keys into client code or public env vars.
- Require review of auth checks on every new route that touches user data or model calls.
- Security checks
```bash # Example CI scan for accidental secret patterns grep -RIn "sk-" . --exclude-dir=node_modules --exclude-dir=.next ``` Use this as a basic tripwire alongside proper secret scanning tools in CI.
- Monitoring
- Alert on abnormal token spend spikes greater than 25 percent day over day.
- Alert on repeated unauthenticated hits to protected endpoints above baseline traffic by more than 50 requests per hour.
- UX guardrails
- Show clear login states before users reach expensive actions.
\n- Explain why access is required instead of failing silently.\n\n- Performance guardrails\n" + " \n" + "- Cache non-sensitive portal data.\n" + "- Keep auth checks cheap so they do not add visible delay.\n" + "- Watch p95 latency after adding middleware so you do not trade security for slow onboarding.\n\n- Dependency hygiene\n" + " \n" + "- Keep Vercel AI SDK and OpenAI client versions current.\n" + "- Review release notes when auth/session libraries change.\n" Access to Vercel,\nyour domain registrar,\nand Cloudflare if already connected.\n2. A list of environments:\ndevelopment,\nstaging,\nand production.\n3. A short note on who should have access inside the portal.\n4. Any known compliance constraints such as EU customer data handling.\n5. The exact pages or flows where AI features should be available.\n\nMy recommendation is simple:\ndon't ship another iteration until auth sits at the API boundary\nand your keys are fully out of reach from browsers.\nIf you want me to fix it quickly with minimal churn,\nLaunch Ready is the right sprint.\n\n## References\n\n- https://roadmap.sh/api-security-best-practices\n- https://roadmap.sh/code-review-best-practices\n- https://roadmap.sh/cyber-security\n- https://vercel.com/docs/environment-variables\n- https://platform.openai.com/docs/guides/production-best-practices
Delivery Map
---
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.*
Cyprian Tinashe Aarons — Senior Full Stack & AI Engineer
Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.