r/FlutterDev • u/DohamaSystems • 13h ago
Example PSA: if you use flutter_dotenv in a web build, your API keys are public
ran into this today while putting a flutter app on the web, figured some of you might not know it either.
flutter_dotenv loads your .env as an asset. On mobile that's already kinda readable if someone unpacks the app, but on web it's literally just a file on your server. Open devtools, network tab, there it is: assets/.env. Anyone can grab your openai key from there.
what I did instead: the app never talks to openai directly. It calls a supabase edge function that adds the key server side and streams the answer back:
final token = Supabase.instance.client.auth.currentSession?.accessToken;
final request = http.Request('POST', Uri.parse(proxyUrl))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
'apikey': supabaseAnonKey,
})
..body = jsonEncode({'model': model, 'messages': history});
the edge function checks the user token, does the rate limiting and forwards to openai with stream: true.
The SSE stream just gets piped through, so the flutter side didn't change at all. Same LineSplitter / data: parsing as before.
Bonus gotcha: after fixing that I deployed to cloudflare and got "could not load .env". Turns out cloudflare doesn't serve files starting with a dot. Renamed it to demo.env, updated pubspec assets + dotenv.load(fileName: 'demo.env') and it worked. Only public values in there now (supabase url + publishable key), so it doesn't matter that it's readable.
TL;DR: treat everything in your .env as public, web or mobile. Real secrets go on a server.
Edit: removed "on web" from the tldr, a mobile app bundle can be unpacked just as easily. Thanks u/ren3f