Sorry, this is a painful way to learn it. What happened: anything with the EXPO_PUBLIC_ prefix is inlined into the JavaScript bundle that ships in your APK. Anyone can unzip the app and search for sk-. .gitignore only keeps it out of git, not out of the app.
Rule: a secret can never live in the app. Not in env, not obfuscated, not split in pieces.
The proper setup:
- App calls your backend (a Supabase Edge Function, a Vercel function, a small server).
- The backend checks who's calling (user must be logged in, verify their JWT).
- The backend holds the OpenAI key and makes the call.
- The backend enforces limits: per user per day, max tokens, allowed model only.
Point 4 is what saves you next time. Even if someone abuses a logged-in account, they're capped.
Also: set a hard monthly limit on the OpenAI project, and ask OpenAI support about the charges, explaining the key was leaked from a client app. No guarantees, but worth asking.