How to hide API Key on Heroku & Github for React Apps

Image from Unsplash

阅读本文前,你需要大致了解:

✅ Git & Github

✅ JavaScript & React

✅ What is API, API Key & Environment Variables


最近做了某家公司的Online Assessment,内容很有趣,通过和第三方API交互设计并实现一个Web App。同时要求deploy在hosting平台上,比如Heroku, Github Pages, Google Cloud等,让用户可以不需要下载代码,直接在网页端运行。

欢迎大家来玩一下我做好的Web App – WeTalk.ai: https://fun-ai-response.herokuapp.com/ 因为本人的OpenAI的API token过期了,加上heroku开始收钱,本人因为抠门这两样东西都没有续费,所以这个web app已经不能用了。哈哈,但是文章还是有用的。

Web App逻辑并不复杂,第三方API的文档也写得很清楚,所以这部分我自信做得还不错。但问题在于找平台deploy我的Web App时出现了问题:如何在隐藏API key的前提下deploy Web App.

与第三方API交互时,对方会给每个提出请求的用户一个单独的API key,在我们写的代码里,需要用到这个API key才能得到对方的数据。而API key由于是每个用户独一无二的密钥,一旦泄露并被人恶意是用,会给平台和用户带来很多麻烦,甚至有可能给平台造成数据安全问题。

因此,在任何时候都不应该把API key直接写在代码里并上传到任何公开平台,包括Github公开的Repository. 有些第三方平台(比如我用的这个)会主动检测网络上是否有暴露的API key并自动替换,导致我的Web App因为换了密钥无法与第三方再沟通。

这一步我花了很多时间,走了一些弯路,最后在搜索多篇教程+猫咪的一起debug下顺利完成了!还要感谢Discord前端群的群友帮助和象友帮助。

在这篇里我会记录一下这次项目中遇到的有用的教程和踩过的坑,希望给后来人一些参考。

我接下来详细介绍的是Create React App + GitHub + Heroku的workflow. 相信其他的deploy service也是相同的原理。


1. Adding Custom Environment Variables in Create React App

设置方法有很多种,取决于使用的前端framework. 一般来说常常会用到npm的dotenv package. 原理是将API key写在 .env 文件中,并不上传到Github,仅供自己本地使用。

因为我这次用的是React bootstrapped with Create React App,它自带了dotenv library,因此不需要再额外安装。具体可见官方文档关于配置Custom Environment Variables的部分

有几点摘要如下:

  • Custom environment variables should begin with REACT_APP_
  • Any other variables except NODE_ENV will be ignored to avoid accidentally exposing a private key on the machine that could have the same name.
  • Changing any environment variables will require you to restart the development server if it is running.
  • access it by process.env.REACT_APP in your React app.

Stack Overflow的一个例子

  • .env文件中 – REACT_APP_BASE_URL=http://localhost:3000
  • service.js中 – const BASE_URL = process.env.REACT_APP_BASE_URL;

2. Hide API Key from Github

配置完成后,需要在repository的root directory的 .gitignore 文件中加入 .env

样例如下:

# misc
.DS_Store
.env

如果之前不小心已经commit或者push过 .env file到自己的repository,那么需要清理一下Git cache. 让最新的 .gitignore 可以track到目前repository任何不应该被track的文件:

  • 如果想untrack single file,只需要 git rm --cached filename
  • 如果想要untrack所有 .gitignore 中的file,步骤如下:
  • First commit any outstanding code changes (否则git add之后其他进度的文件会消失)
  • run git rm -r --cached . (This removes any changed files from the index
  • staging area)
  • then run git add .
  • then commit: git commit -m ".gitignore is now working"

链接中的注意事项里也提到了,再从git上pull下来的时候这些 .gitignore 中的文件就不会存在了,所以请做好本地处理。

另外,可以在repository中加上 .env.example 告诉其他developer该如何配置app中用到的key value pair.


3. Deploy on Heroku using Git

接下来需要聊聊deploy的问题。这次我尝试了Github Pages和Heroku.

最终Github Pages没有成功,我怀疑是我使用的第三方API专门track了Github来的request并且禁止了。每次我一部署在Github Pages上,我的API key就会被认为泄露,并自动更换,造成了很多痛苦。

如果碰到了可以接受Github Pages的第三方API,可以直接照着Github Pages的deployment来设置,也可以遵循Create React App官方的Github Pages deployment部分进行配置。推荐照着后者的教程,因为可以在deploy之后继续开发,不需要反复deploy,操作非常丝滑。

Github Pages配置Enviroment Variables的部分请参照Discord群的22Chestnut的提供的教程,感谢帮助。


之后我转战了Heroku. 首先如果在别的平台deploy过并按照CRA官方文档修改过 package.json请记得要改回来!我在这部分卡了好久,恢复以后就好了。

接着根据CRA的官方文档来deploy with Heroku.

  • 首先安装Heroku CLI. 我是PC,其他方法我怎么都配置不成功,所以最后用了官方不推荐的npm,最后也成功了。
  • verify installation – heroku --version
  • 跟着步骤login – heroku login

之后就是deploy到Heroku上。如果想在创建app之前就连好Heroku的deployment,需要follow这个教程

我因为已经在安装Heroku之前创建了App,所以步骤略有不同,省略了前几步。

git init # 当时我copy到了一个新的repository里,还没有传到Github上,因此需要init.
heroku create -b <https://github.com/mars/create-react-app-buildpack.git>
git add .
git commit -m "react-create-app on Heroku"
git push heroku master
heroku open

因为Heroku官网的教程和该developer自己的教程出现了一些不同:git push heroku mastergit push heroku main 的区别,我没注意到,因此有了一个报错,最后使用了这个Stack Overflow的办法解决了。

git push heroku HEAD:master 或者 git push heroku HEAD:main 取决于想要用哪个branch deploy.

原理参见这个帖子。指明了用当前的repo来commit到我要deploy的branch.


4. Pass API Key to Heroku through Environment Variable

那么文件都deploy上Heroku了,但是如我之前所说, .gitignore 中的文件包括包含了我API key的 .env并不会被commit到任何repository里。之后怎么将我的API key告诉Heroku呢?

答案是我通过Heroku的方式偷偷告诉它。有两种方式:一种是通过Heroku CLI,一种通过Heroku Dashboard. 参见这篇官方教程

如果是用的React,也可以看这里的教程, 本质上都是一样的。

我用的是terminal command – heroku config:set REACT_APP_HELLO='I love sushi!'

注意读文档的时候不能掠过信息,比如这里: The app must be re-deployed for compiled changes to take effect, because during the build, these references will be replaced with their quoted string value.

因此不管用哪种方式配置了我的API Key,我都需要重新deploy一次。

git commit --allow-empty -m "Set REACT_APP_HELLO config var"
git push heroku main

对于git repository来说,我们没有增删改减任何文件,所以直接 git add .git commit -m "re-deploy" 的话并不会触发heroku的re-deploy.

所以记得commit的时候一定加上 --allow-empty 才会有效果!


5. Sync between Heroku and Github

为了保险起见,commit + push完heroku之后,commit到Github也请加上 --allow-empty 保证能顺利commit.


Reference

最后附上我这次的repository供参考 –

GitHub Repo

并欢迎大家来玩我的Web App – WeTalk.ai: https://fun-ai-response.herokuapp.com/

感谢猫咪的一路帮助和安抚。