How I Would Fix exposed API keys and missing auth in a React Native and Expo client portal Using Launch Ready.
The symptom is usually obvious before the root cause is. A founder notices that the app still works even when someone opens the JS bundle, inspects...
How I Would Fix exposed API keys and missing auth in a React Native and Expo client portal Using Launch Ready
The symptom is usually obvious before the root cause is. A founder notices that the app still works even when someone opens the JS bundle, inspects network calls, or signs in from a fresh device without being challenged properly, and then realizes API keys are sitting in the client and sensitive portal data is reachable with weak or missing auth.
The most likely root cause is that the app was built fast in Expo and the backend trust model was never enforced. The first thing I would inspect is the actual data path: what is stored in the app bundle, what endpoints are public, and whether the server is verifying identity and permissions on every request.
Triage in the First Hour
1. Check the live app behavior on a clean device.
- Log out, clear storage, reinstall, and try to access portal screens directly.
- Confirm whether private data loads before a valid session exists.
2. Inspect network traffic from one real user flow.
- Look for API calls returning customer records without a bearer token.
- Check whether role checks happen only in the UI instead of on the server.
3. Review Expo environment handling.
- Search for `EXPO_PUBLIC_` variables and any hardcoded keys in source.
- Confirm whether secrets were baked into the JS bundle during build.
4. Audit the deployed backend routes.
- Identify which endpoints are public, which require auth, and which should be admin-only.
- Verify middleware order so auth runs before business logic.
5. Check cloud and deployment accounts.
- Review API provider dashboards for exposed keys, unusual usage spikes, or unexpected referrers.
- Rotate any key that may have been committed, bundled, or shared with third-party tools.
6. Inspect logs and monitoring.
- Look for 401s, 403s, repeated anonymous requests, and suspicious data export patterns.
- Confirm whether errors leak stack traces or internal IDs to clients.
7. Review recent builds and releases.
- Identify when auth broke: last code push, config change, or new environment variable.
- Compare staging versus production behavior if both exist.
A simple diagnosis command I often use during triage:
grep -R "sk_" . \ && grep -R "api_key" . \ && grep -R "EXPO_PUBLIC_" .
This does not fix anything by itself, but it quickly tells me whether secrets are living where they should never live.
Root Causes
| Likely cause | What it looks like | How I confirm it | |---|---|---| | Secrets embedded in Expo client code | API key appears in JS bundle or repo history | Search source, inspect built assets, review git history | | Backend trusts the frontend | Private endpoints respond without valid session checks | Call endpoints from a clean client with no token | | UI-only authorization | Screens hide content visually but APIs still return data | Test direct API access to restricted resources | | Misconfigured environment variables | Dev keys shipped to production build | Compare `.env`, EAS config, and production runtime values | | Weak session handling | Users stay logged in too long or can reuse expired tokens | Test logout, token expiry, refresh flow, and device changes | | Over-permissive third-party key scope | One leaked key can read too much or mutate data | Review provider permissions and usage logs |
The biggest mistake I see is assuming "the app hides it" equals "the system protects it." If the backend does not enforce auth on every request, then any motivated person can bypass the UI entirely.
The Fix Plan
First, I would freeze risky changes until access control is corrected. That means no new features until we know which endpoints are public by design and which ones must be locked down.
Then I would separate public configuration from secret material. In React Native and Expo, anything shipped to the device should be treated as visible to users; true secrets belong on a server or edge function behind authenticated APIs.
Next I would move sensitive operations behind a backend layer:
- Replace direct client calls to third-party services with server-side endpoints.
- Keep service credentials in server environment variables only.
- Issue short-lived tokens for user sessions instead of static long-lived secrets.
Then I would enforce authentication at the API boundary:
- Require a valid session token on every protected route.
- Verify user identity first, then verify tenant membership or role.
- Return 401 for unauthenticated requests and 403 for unauthorized ones.
I would also tighten account recovery and session hygiene:
- Rotate all exposed keys immediately.
- Invalidate old sessions if compromise is possible.
- Shorten token lifetime where practical and add refresh logic only if needed.
For Expo specifically, I would check build-time config carefully:
- Remove any secret from `EXPO_PUBLIC_` variables if it must stay private.
- Audit `app.config.js`, EAS secrets, native modules, analytics tags, and crash reporting setup.
- Rebuild from clean environment variables after rotation so no stale secret survives in artifacts.
If there is no backend yet, I would not fake security with client-side checks. I would add a minimal auth service first rather than shipping another version that still exposes customer data through guessable routes or public APIs.
Here is how I would sequence it in practice:
That order matters. If you rebuild before rotating exposed keys or fixing authorization checks, you just produce a cleaner version of the same security problem.
Regression Tests Before Redeploy
Before shipping anything back to users, I want proof that unauthorized access is blocked and authorized access still works.
My minimum QA checklist: 1. Fresh install test
- Install on a clean device with no cached session.
- Confirm protected screens do not load private data before login.
2. Unauthorized API test
- Call each protected endpoint without a token.
- Expect 401 responses consistently.
3. Wrong-role test
- Use a normal client account against admin-only actions.
- Expect 403 responses with no leaked details.
4. Token expiry test
- Expire or revoke a token manually if possible.
- Confirm the app forces re-authentication cleanly.
5. Secret scan
- Re-scan source code, build output, release notes, analytics tags, and logs for hardcoded keys.
- Confirm nothing sensitive appears in client bundles.
6. Data isolation test
- Switch between two different portal accounts.
- Verify one tenant cannot see another tenant's records by changing IDs or navigating directly.
7. Error handling test
- Break auth on purpose once and confirm users get a safe message instead of stack traces or raw backend errors.
Acceptance criteria I would use:
- Zero exposed production secrets in client code or bundles.
- All protected routes return 401/403 correctly when unauthenticated or unauthorized.
- No private portal data loads before login.
- No cross-account data access across at least 10 manual test cases.
- Build passes with no critical security warnings left unresolved.
If this were my handoff standard, I would also want at least one successful redeploy from clean CI with rotated credentials already verified in production-like settings.
Prevention
I prevent this class of issue by making security part of delivery instead of an afterthought.
My guardrails:
- Code review rule: no secret may live in mobile code unless it is truly public by design.
- Auth rule: every protected endpoint must verify identity server-side before touching data.
- Logging rule: never log tokens, passwords, signed URLs with long lifetimes, or raw PII.
- Release rule: rotate any key that touched source control or client builds immediately after discovery.
- Monitoring rule: alert on unusual request volume, repeated 401s from one IP range, failed login spikes, and unexpected API quota use.
- UX rule: show clear login expiration states so users do not think "broken app" when they actually need to re-authenticate.
- Performance rule: keep auth middleware fast so security does not create slow p95 response times above 300 ms on normal portal actions.
I also recommend simple security review gates before release:
- One reviewer checks auth boundaries only.
- One reviewer checks secret handling only.
- One reviewer verifies that frontend state does not imply backend permission.
For Expo apps specifically:
- Treat mobile code as hostile territory from day one.
- Use backend-issued tokens with short lifetimes where possible.
- Move all privileged operations off-device unless there is a strong reason not to.
When to Use Launch Ready
Launch Ready fits when you already have a working React Native or Expo portal but need it made production-safe fast. If your problem includes exposed API keys, missing auth, broken deployment, unclear DNS, SSL issues, or shaky monitoring,
What Launch Ready includes:
- DNS setup
- Redirects and subdomains
- Cloudflare configuration
- SSL setup
- Caching rules
- DDoS protection
- SPF/DKIM/DMARC email setup
- Production deployment
- Environment variables
- Secrets handling
- Uptime monitoring
- Handover checklist
What you should prepare before booking: 1. Repo access for web app and backend if separate. 2. Expo/EAS access if mobile builds are involved. 3. Domain registrar access and Cloudflare access if applicable. 4. Hosting credentials for Vercel, Netlify, Render, AWS, Supabase, Firebase, or your current stack. 5. A list of all third-party services used by the portal: auth provider, payments, email, analytics, and storage buckets. 6. One clear description of who should be able to see what inside the portal.
If your issue is "we shipped too fast and now customer data might be exposed," this is exactly the kind of rescue sprint I run. The goal is not just to patch symptoms; it is to get you back to something you can launch without creating support load, downtime, or an app store rejection later.
References
1. Roadmap.sh Cyber Security Best Practices: https://roadmap.sh/cyber-security 2. Roadmap.sh API Security Best Practices: https://roadmap.sh/api-security-best-practices 3. Roadmap.sh QA: https://roadmap.sh/qa 4. Expo Environment Variables: https://docs.expo.dev/guides/environment-vars/ 5. OWASP API Security Top 10: https://owasp.org/www-project-api-security/
---
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.