38

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:

Folder tree

-lib
  -auth
    -keys.dart
    -secrets.json 

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"
}

keys.dart

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.

Philip Mutua
  • 4,150
  • 5
  • 23
  • 48
  • 1
    If this shouldn't be shared; ideally it shouldn't be on the client. Ultimately once you ship your app, peoples can just decompile it to get everything within. – Rémi Rousselet Aug 17 '18 at 12:21
  • I'm using an API that requires me to add the key so that I get the payload I need. The app is consuming the API and add a key is required to access the payload. Where can I store the keys so that I access them when needed? – Philip Mutua Aug 17 '18 at 12:32
  • I like this method of doing things. I've done very similar things in my apps. I will also make a `main_dev.dart` and `main_prod.dart` -- each file will be targeted for running that version of the app. In each file, i will import the corresponding `secrets.json` and use it throughout the app. – MaylorTaylor Jul 21 '19 at 04:20
  • how are you actually retrieving the api key string in your code? – fiixed Nov 16 '19 at 20:59
  • 2
    if you rely on gitignored file with secrets, just make a dart file with `static const` keys. Much easier to use – zgorawski Jun 22 '20 at 06:07

4 Answers4

10

Edit: Look at J. Saw's comment below

Use Firebase Remote Config. Inside the Firebase console, inside the menu, scroll down to 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.

enter image description here

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.

Noodles
  • 2,011
  • 1
  • 17
  • 25
  • 4
    I like this strategy. However, then you have documentation like https://pub.dev/packages/google_maps_flutter#getting-started that tells people to place the API KEY in `AndroidManifest.xml` or `AppDelegate.m`. Is this not bad practice? How should one replace this strategy? – AWhitford Feb 22 '20 at 16:40
  • 17
    Per Firebase: "Don't store confidential data in Remote Config parameter keys or parameter values. It is possible to decode any parameter keys or values stored in the Remote Config settings for your project." (https://firebase.google.com/docs/remote-config) – J. Saw May 21 '20 at 12:31
9

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:

Android Keystore

iOs KeyChain

Also, you can use this flutter plugin, which uses the services mentioned above and provides a dart object to access the secure storage.

Rolando Urquiza
  • 1,096
  • 1
  • 13
  • 26
2

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/

Gainz
  • 911
  • 1
  • 5
  • 9
  • 2
    I do not want to invest extra time building a back-end server for this, I did my research and found out how android handles this when building it with java :(https://stackoverflow.com/questions/14570989/best-practice-for-storing-and-protecting-private-api-keys-in-applications). There must be a way for flutter to handles this. Also here https://github.com/codepath/android_guides/wiki/Storing-Secret-Keys-in-Android – Philip Mutua Aug 17 '18 at 14:17
  • 8
    But if you request the API from your own server everyone will be able to do that if they know the URI that they could again retrieve from your code. – Noodles Aug 06 '19 at 15:03
-1

You can use flutter_secure_storage from the oficial Flutter Packages

Álvaro Agüero
  • 2,458
  • 32
  • 26
  • 5
    Possibly a stupid question, but when using this package, I will still rely on putting the keys in my source code, since they eventually have to be added to the secure storage at some point, so I can read them later. Or am I misunderstanding something here? – Thomas Jun 13 '19 at 11:44
  • 6
    I think you understand it correctly. That package helps if you get secrets from your *user* and want to store them safely. – harm Jul 17 '19 at 08:53