Search code examples
reactjsgithubcreate-react-appgithub-pagesgithub-actions

Embed GitHub Secret in React and Deploy to GitHub Page Revealed my Personal Access Token


My goal: my react app has an environment variable to store a Github Personal_Access_Token(later used in HTTP header for a fetch), then I will later deploy the app to Github page using Action Workflow.

What I tried: Given that pushing/exposing token as plain text to Githut is a violation, I would use Github secrets to avoid it. I found this post and tried to implement Github Workflow to access the secret then deploy.

- name: Install and Build 
  run: |
      npm install
      npm run-script build
  env:
      REACT_APP_GITHUB_ACCESS_TOKEN: ${{ secrets.REACT_APP_GITHUB_ACCESS_TOKEN }} // this is what I need


- name: Deploy 
  uses: JamesIves/[email protected]
  with:
     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
     BRANCH: gh-pages
     FOLDER: build

Issue: After the successful run of the workflow, I found out that the token was auto-revoked by GitHub because it was showing up in the build/static/js/xxxx.chunk.js, and pushed to the gh-page branch:

{headers:{Authorization:"token ac4455aXXXXXXXXXXXXXXXXXXXf80512f3e"}}

This was not what I expected, but I understood the secret was accessed and embedded during the build and got put into the static build folder.

Could someone please point me the direction as in, did I do anything wrong in the workflow? Or was the workflow never meant to be a solution to my problem and I should never use GitHub pages to host a pure react app that uses a secret token?
Thanks in advance.


Solution

  • The problem is that React is purely a front-end framework. Everything that should be available directly in React is also available to your users to see. There's no way around this!

    To really keep the secret private it has to be somewhere server side and not on the front-end. One way you could do this is make a "serverless function" (there are multiple generous free offers available on different services). Then you proxy through there, which basically means that:

    1. Your react front-end fetches from your serverless function without any secret.
    2. Your serverless function has the secret stored and does the same fetch on the actual service with secret.
    3. Your serverless function can now return the response it got back to your React front-end.