Back to course overview
Module 5Putting AI inside your app 14 min

Securing API keys with a backend proxy

Why you must never ship an API key in your app, and how to stand up a tiny proxy that keeps the secret safe.

Read this before you ship anything

Never embed a secret API key in an iOS app. Anyone can extract strings from a downloaded app binary in minutes. A leaked key can be used to run up thousands of dollars of charges on your account. This is the single most important security lesson in the course.

The solution is a proxy: a tiny server you control that holds the secret key. Your app calls your server; your server adds the key and calls the model. The key never leaves your infrastructure. That's why InsightsService in the last lesson called apiBase/reflect instead of Anthropic directly.

The architecture

  1. iPhone app → HTTPS POST to your proxy with just the entry text. No secrets.
  2. Your proxy (a serverless function) → adds ANTHROPIC_API_KEY from a secure environment variable, calls the model, returns JSON.
  3. The model provider → only ever talks to your server, which you can rate-limit and monitor.

Standing up the proxy

The fastest path is a serverless platform with a free tier (e.g. Vercel or Cloudflare Workers). You deploy the reflect function from the last lesson, set the API key as a secret environment variable in the dashboard (never in code), and you get an HTTPS URL like https://dayone-proxy.vercel.app/api. The walkthrough below uses Vercel. Alongside api/reflect.js, your proxy needs exactly one more file — a minimal package.json that declares the Anthropic SDK dependency:

package.jsonjson
{
  "name": "dayone-proxy",
  "private": true,
  "dependencies": {
    "@anthropic-ai/sdk": "latest"
  }
}
  1. 1Install Node.js from nodejs.org — download the LTS installer and run it like any Mac installer. This gives you the npm command the next steps use.
  2. 2Create a folder called dayone-proxy anywhere you like. Inside it, create a subfolder api containing reflect.js (the code from the last lesson), and save the package.json above at the folder's root.
  3. 3Create a free account at vercel.com.
  4. 4In Terminal, run npm i -g vercel, then cd into dayone-proxy and run vercel. Follow the login prompts — it deploys the folder and prints your URL.
  5. 5Add your API key in the Vercel dashboard: your project ▸ Settings ▸ Environment Variables, name ANTHROPIC_API_KEY, value the key you created last lesson. It stays server-side.
  6. 6Run vercel --prod to redeploy with the key in place.
  7. 7Test it — open Terminal and paste (curl comes with macOS): curl -X POST https://your-proxy/api/reflect -d '{"entry":"Rough day"}' -H 'Content-Type: application/json'.
  8. 8Put the resulting base URL in your app's config (below) — this value is not secret.
AppConfig.swiftswift
enum AppConfig {
    // The proxy base URL is safe to ship — it contains no secret.
    static let apiBase = URL(string: "https://dayone-proxy.vercel.app/api")!
}
Add rate limiting on the proxy

Because the proxy is yours, put limits there: cap request body length, and reject bursts from a single client. Ask your assistant to "add a simple in-memory rate limiter and a 16KB body cap to this serverless function." (Keep the proxy cap comfortably above the app's own entry-length limit — the ~4,000-character cap from the Module 5 lab is well under 16KB even after JSON-escaping and emoji.) It protects your wallet regardless of app bugs.