Managing secrets in an open-sourced flutter web app
In this blog post, I would like to share how you can use GitHub actions to deploy your open-sourced Flutter web app without exposing any secrets or API keys that are crucial to your application. This approach can be used for any frontend framework and not just flutter.
Building the User interface of your application is often fun, But once you start integrating the dopamine for fun starts to reduce as you start integrating services, especially when security is a great deal for your product or when you are building a feature that includes dealing with sensitive data in your backend or other services that power the backend of your application. You generally need to manage API keys, JSON files, or secrets that your frontends need to depend on. Passing these keys to your front end is cumbersome and can put your application at risk if not handled carefully. Extra care should be taken when your project is publicly available. Do not worry in case you accidentally push your secret to GitHub you can safely remove it, Keep reading to find out how.
I wanted to develop a vocabulary app that is open-sourced and at the same time, I wanted it to be secure and wanted to make sure the app gets deployed without exposing the keys. This vocabulary app uses supabase in the backend, which is an open-sourced firebase alternative that provides a serverless solution that can get up and running in less than 2 minutes. In order to access the supabase database, it provides us with few keys which are unique to your application basically anyone with those keys could access the database, So you have to make sure those keys are safely stored.
Problem
There were two challenges to make the project publicly available on Github
- I have stored all those confidential keys into my flutter app in a constant file and the application can fetch those keys from that file and the app works fine locally, But the problem comes when we want to push the code to GitHub, since we cannot expose the keys publically.
- Another problem is that the app uses flutter-action by subosito which is basically a CI solution using GitHub actions that automatically runs a script and deploys my flutter webapp on each commit by running some build commands, You can find the complete script here. But it is obvious that the build would fail if it finds if any of the pieces of the code are missing from the repository (Our secret keys in this case)this means the app won’t get deployed.
Basically, these two things wouldn’t allow my app to be deployed securely.
Solution
So for this Github Encrypted Secrets comes to the rescue if you go to any repository under settings you will see an option called secrets which basically allows you to store any sensitive information in your organization, repository, or repository environments which can be accessed in GitHub Actions workflows.
But there is another problem
The problem is you cannot access those encrypted secrets in your application, had it been the case the problem would have been solved and I would have called it a day 👋🏻. I searched a little about it but couldn’t find any solution which will allow you to access the encrypted secrets but since we have been using this amazing Q&A platform for devs called “StackOverflow” which helped me get an answer. Here is that stackoverflow question that I asked and I got a simple and amazing answer to that. Thanks to this user Xamantra for the solution.
Tell me the solution
The solution is to
1. encode your confidential file to base64 and store the encoded output to GitHub secrets.
2. In your GitHub workflow decode the encrypted secret and convert it back to a file and then run your build scripts.
It's that simple
Now you can add your confidential files to .gitignore and never push it to the repository since now you have GitHub encrypted secrets.
Show me how it's done
Here is how we do it step by step
1. convert your secret file to base64 the file can be of any type. I had a dart file which has the api keys stored so convert it to base64 using this command
base64 lib/path/to/secrets.dart
This will give you a base64 string copy that string and add it to GitHub secrets as shown in the below picture.
2. Now in your workflow script before you run the build command decode the base64 and convert it back to file with the path where it needs to be created.
run: echo $YOUR_SECRET_KEY | base64 -d > lib/somedirectory/secrets.dart env: YOUR_SECRET_KEY: ${{ secrets.YOUR_SECRET_KEY }}
And that's it, folks! that is it! you will see your build running successfully and the app getting deployed to the web, safe and secure with open-sourced code.
But there is one more problem what if you delete your local repository how do you get back those keys that you never pushed to Github?
That is still a mystery to me apart from the manual decoding let me know if you have a solution to this problem. More on this later sometimes if I find a solution.
Now let's talk about a case when you push your secrets to GitHub, regardless of whether it's a public or private repo, you can still remove that particular commit, See this StackOverflow answer on how to safely remove your commit without leaving any traces of your secrets.
Here is a link to the repository in case you would want to check it out.
Repository:https://github.com/maheshmnj/vocabhub
Successful Builds: https://github.com/maheshmnj/vocabhub/actions
Thanks for reading till the end.
Have a great day.
Follow Flutter Community on Twitter for more great articles: https://twitter.com/FlutterComm