Reputation: 6881
Which is the correct way(best practice) of adding secret API keys in flutter in case I want to push the code on github. I've made a simple app that consumes an API but I used the key in a crud way just to test whether the app is working. Usually from my experience developing applications in the back-end, Keys are stored somewhere and in different file then one would simply import it to the required file that needs the API_KEY
and exclude the file in .gitignore
file.
So far I have also implemented this approach:
-lib
-auth
-keys.dart
-secrets.json
This is where I will add the KEY
and specify this file in .gitignore
to be excluded from being added in github when I push my code.
//Add API KEY HERE
{
"api_key": "ee4444444a095fc613c5189b2"
}
import 'dart:async' show Future;
import 'dart:convert' show json;
import 'package:flutter/services.dart' show rootBundle;
class Secret {
final String apikey;
Secret({this.apikey=""});
factory Secret.fromJson(Map<String, dynamic>jsonMap){
return new Secret(apikey:jsonMap["api_key"]);
}
}
class SecretLoader {
final String secretPath;
SecretLoader({this.secretPath});
Future<Secret> load() {
return rootBundle.loadStructuredData<Secret>(this.secretPath,
(jsonStr) async {
final secret = Secret.fromJson(json.decode(jsonStr));
return secret;
});
}
}
I feel like this approach is too much. I would like to get suggestions of a better approach.
Upvotes: 89
Views: 59673
Reputation: 77
we should not store secret keys in a file because it is easy to decompile. You can try these methods
Upvotes: -1
Reputation: 4749
We are using the Flutter DotEnv package for this.
Include this package in pubspec.yaml
flutter_dotenv: ^5.1.0
Create a file named .env
in root folder. Register this .env
file as a asset
assets:
- .env
Add loading of dotenv in your main function before loading the app void main() async { await dotenv.load(); }
Add the .env
file in .gitignore
file so it shouldn't be commited
Now add the required keys in the .env
file, for e.g.
dev_firebase_remote_config_api_key=apikey_124433
sit_firebase_remote_config_api_key=apikey_1243734
uat_firebase_remote_config_api_key=apikey_1248262
These env config can be read in the code using.
import 'package:flutter_dotenv/flutter_dotenv.dart';
and now read the config
dotenv.env['dev_firebase_remote_config_api_key']!
Please refer Flutter DotEnv for more details
Upvotes: 0
Reputation: 734
You should never put API keys into your client apps (unless they are marked as public keys), as mentioned above they are now compromised and could be used in malicious context. Additionally, it's generally a good idea to be able to roll-over api-keys, secret-keys periodically. Embedding them into your client apps just about kills that notion without some complex mechanism that in-itself will be an anti-pattern.
What we should be doing:
As far as the backend, server-side impl. It can be as simple as a server-less function such as an AWS Lambda + API Gateway (1Million executions a month for free from Lambda). Or you can host larger, more complex service backends if needed.
Upvotes: 1
Reputation: 1
A way of storing API Keys safely in flutter local repository from not being uploaded to a remote repository, is to use dart package flutter_dotenv, here I put the link of the package with all the information about it link to package
Upvotes: 0
Reputation: 4080
EDIT: Look at Sludge's comment below.
EDIT 2: The issue in described at the bottom has been fixed in firebase-config 19.0.2
.
Use Inside the Firebase console, inside the menu, scroll down to Firebase Remote Config
.Grow
and then Remote Config
. Here you can add a parameter with a value. When you're done don't forget to publish the changes. It's kind of subtle.
Now install firebase_remote_config for Flutter.
After importing everything, you can retrieve your value using this code:
RemoteConfig remoteConfig = await RemoteConfig.instance;
await remoteConfig.fetch(expiration: Duration(hours: 1));
await remoteConfig.activateFetched();
remoteConfig.getValue('key').asString();
This way, the API key or token is never part of your application.
Note: there is currently an issue where you get a warning stating the application's name is not set, but this won't affect functionality.
Upvotes: 7
Reputation: 345
The best practice should be to create a Firebase function, and then have that function use the secrets storage. This approach keeps the secrets out of your source code so there are no issues with sharing the code, and stores them securely. Firebase authenticates your app (and users if you use the login feature).
Upvotes: 3
Reputation: 7118
Because it's impossible to retrieve the key from an external source without having a key to that source, and you can't store it securely at the OS level without having the key within the app.
When you connect your app to a Firebase project or Google Cloud servers, you basically authenticate using a hard-coded API key, that you have downloaded into your app when initiating your cloud project (read more).
There are two essential steps to secure your critical assets:
IMO, those are the only steps you can take to secure your app API Key.
Upvotes: 27
Reputation: 4800
You can use flutter_secure_storage from the oficial Flutter Packages
Upvotes: -4
Reputation: 1450
For secure storage you have to rely on the corresponding native platforms, both iOs and Android provide a mechanism to securely store keys. You can implement it by yourself and use the flutter channels to obtain and store the keys. Information about this mechanism can be read here:
Also, you can use this flutter plugin, which uses the services mentioned above and provides a dart object to access the secure storage.
Upvotes: 8
Reputation: 1799
As mentioned, if the key is a secrete and you would like to protect it then simply do not put it in the client app. The app can be de-compiled and the key can be extracted for person willing to target your client.
I would delegate the task of communicating with this API to your Application Server. You can put the key in your server and have your server communicate with this external API and relay the response to the client.
Edit: Another approach, which is less secure but more convenient is to obfuscate your code using something like proguard. See this page for flutter instruction on android app: https://flutter.io/android-release/
Upvotes: 5