How to secure API keys in Flutter

Nahit FIDANCI
4 min readNov 1, 2023

--

Secure API key with envied

Hello everyone, it’s been a while since I wrote my last article. I felt like it ‘s time to write something new and useful. So, here we are. You can check out my previous articles below.

Some of you might not be aware of that but almost anything bundled in your app’s build can be demystified. It includes your commented test account credentials, funny todos, a grocery list that you committed by mistake, and your API keys. Yes, some of you still store groceries in your projects.

What would be a better move?

We can use .env files to store our secrets. And then we can access them easily. Check out flutter_dotenv for more. This approach is better but it is much easier to demystify secrets. Why? Because we have to add .env files to pubspec.yaml as assets to access them in dart files. Why is it a bad thing? Because assets can be reached easily without any decryption or other fancy reverse-engineering magics.

You can simply use Android Studio’s APK analyzer to see each resource even if — obfuscate flag is used, assets can still be accessible easily. So, your secrets are not safe.

Flutter Assets

What would be a smarter move?

Well, have you ever heard about environment variables? Yes, I am talking about them. You can pass critical information such as your anniversary through environment variables. Add — dart-define into your toolArgs of you launch.json file in VS Code. And then access them with String.fromEnvironment('NAME');

print(const String.fromEnvironment('ANNIVERSARY'));

You can do the same in Android Studio too.

So, did we solve the problem? Not so fast. This is a good starting point and it will help you to secure your secrets. But it is not a best practice since you give everything through your run configurations. Of course, there are workarounds like passing all the data through a file with — dart-define-from-file . And you can add it .gitignore and you are good to go. But hear me out. There is a better way.

Meet our rockstar: Envied

Envied is the best option so far for ME.

Why?

It is safe because we don’t add .env files as assets. It is safe because it generates dart files which include your credentials in base64 format which makes it harder to decompile and find the secrets. Of course, you need to use obfuscate=true to enable obfuscation.

It is officially supported to use different flavors but I will show you how to do it in the right way.

Let’s create a blueprint for both flavors.

Blueprint for flavors

Remembered String.fromEnvironment ? We give ENV key to define which flavor we want to use. And AppSecret will return that flavor’s secrets.

Let’s see inside of ProductionSecret . First, we need to add part to generate secrets from the environment file. We need to use @Envied annotation with the path of the environment and obfuscate=true .

We implement AppSecret and AppEnvFields, therefore, we agree with what keys should be overriding and AppSecret has exact same secret. So, we can use them without breaking anything in different flavors.

Due to obfuscate=true each key should be final . And each should have @EnviedField with the secret’s key name in the environment file. Which is SECRET_KEY in our case.

Then we say _ProductionSecret.secretKey which will come from the generated file.

Lastly, we need to run one of the below commands.

# dart
dart run build_runner build
# flutter
flutter pub run build_runner build

Do not forget to add .env, production_secret.dart and production_secret.g.dart into .gitignore . You don’t want to store these in your repository.

How to use secrets in CI/CD flows?

If you use a CI/CD tool such as Github Actions or CodeMagic, you need to store your keys in these platforms and dynamically generate envied files in the workflow. You can check out the below link to see how to do it in CodeMagic.

Conclusion

Well, that’s pretty much it. I hope you learned something useful today. Still, I do not recommend you to store the nuclear codes with envied just in case.

Don’t forget to follow me, give claps, and share the article if you found it helpful.

Thank you for reading.

Website

Youtube

Github

LinkedIn

Twitter

--

--

Nahit FIDANCI
Nahit FIDANCI

Written by Nahit FIDANCI

Mobile Developer | Flutter | SwiftUI @nahitfidanci.com

Responses (3)