Integrating 3rd-party APIs into Jamstack apps and websites becomes a bit tricky when the access tokens for these services need refreshing recurrently. Manually refreshing these access tokens and updating the corresponding secrets is one option, but automating the process via a scheduled GitHub Workflow—though adding complexity—gives you one less thing to worry about. Using the Instagram Basic Display API as a basis, I'm going to walk-through an example of automating this process.
Create an Encrypted Secret
The first step is to add an existing (valid) access token to your repository as an encrypted secret. It appears to be a convention to use UPPER_CASE_SNAKE_CASE
when naming these secrets, so I've assigned my access token for the Instagram Basic Display API to a secret named INSTAGRAM_ACCESS_TOKEN
.
Pass a Secret as an Environment Variable
The context in which I'll be using this access token within my Jamstack website is an axios request querying the Instagram User Media endpoint, e.g.:
const response = await axios.get(
`https://graph.instagram.com/${instagramUserId}/media`,
{
params: {
access_token: process.env.INSTAGRAM_ACCESS_TOKEN,
fields: options.fields.join(",")
}
}
);
For process.env.INSTAGRAM_ACCESS_TOKEN
to be referencing the correct value at runtime the environment variable INSTAGRAM_ACCESS_TOKEN
must be present at build time. As part of a Continuous Deployment workflow, I assign the encrypted secret INSTAGRAM_ACCESS_TOKEN
as an environment variable (of the same name) to the build step:
# .github/workflows/deploy.yml
name: Continuous Deployment
on:
push:
branches:
- master
jobs:
deploy:
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- uses: bahmutov/npm-install@v1
- run: yarn build
env:
NODE_ENV: production
INSTAGRAM_ACCESS_TOKEN: ${{ secrets.INSTAGRAM_ACCESS_TOKEN }}
Create a Scheduled Workflow
Long-lived Instagram access tokens will last 3 months, but must be refreshing within 2 months of the date they're issued. If we forget to update the INSTAGRAM_ACCESS_TOKEN
secret on this repository within that time the yarn build
command will fail. To prevent this from happening we can create an additional GitHub Workflow that refreshes the Instagram access token and updates the corresponding repository secret on a schedule.
In a "here's one I made earlier" fashion, I've already created GitHub Actions for refreshing Instagram access tokens and updating GitHub secrets. Be sure to follow the installation instructions in those packages' respective READMEs. One thing to note is that a Personal Access Token (PAT) with the 'repo' scope is required to create or update GitHub Secrets via the GitHub API.
With the action packages installed and a PAT set to a secret named PERSONAL_ACCESS_TOKEN
we can now setup a scheduled GitHub Workflow:
# .github/workflows/instagram.yml
name: Refresh Instagram Access Token & Update GitHub Secret
on:
schedule:
# https://crontab.guru/#0_0_1_*_*
- cron: "0 0 1 * *"
jobs:
instagram:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- uses: bahmutov/npm-install@v1
- name: Refresh Instagram Access Token
id: instagram
uses: ./node_modules/@saulhardman/refresh-instagram-access-token
with:
access_token: ${{ secrets.INSTAGRAM_ACCESS_TOKEN }}
- name: Update GitHub Secret
uses: ./node_modules/@saulhardman/update-github-secret
with:
secret_name: INSTAGRAM_ACCESS_TOKEN
secret_value: ${{ steps.instagram.outputs.access_token }}
access_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
An bonus step that I often include in workflows like these is to send a Pushover notification on success or failure. Passing the access token as part of the success payload gives me the opportunity to update my local development .env
file, too.
A Note on Netlify
As far as I'm aware, Netlify doesn't have an API for managing environment variables (in the free tier, at least). If your project is private and you live life fast and dangerous you could read and write an access token from and to a .env
file that you then commit back to the repository:
- uses: falti/dotenv-action@v0.2.4
id: dotenv
- name: Refresh Instagram Access Token
id: instagram
uses: ./node_modules/@saulhardman/refresh-instagram-access-token
with:
access_token: ${{ steps.dotenv.outputs.instagram_access_token }}
- uses: TickX/var-to-dotenv@v1.1.1
with:
key: INSTAGRAM_ACCESS_TOKEN
value: ${{ steps.instagram.outputs.access_token }}
default: ${{ steps.dotenv.outputs.instagram_access_token }}
- name: Commit Updated DotEnv
uses: EndBug/add-and-commit@v4
with:
message: "chore: refresh instagram access token"
add: .env
env:
GITHUB_TOKEN: ${{ github.token }}
Local Testing
I often develop new Workflows on a feature branch and configure them to run on push
until they're ready to be merged into the primary branch. A less cumbersome option is to use act
to debug Workflows locally.
Closing Thoughts
Automation can be a double-edged sword, but for processes like this GitHub Workflows are a blessing for a front-end web developer working with the Jamstack. How do you manage access tokens? How are you using GitHub Actions to extend the Jamstack?
Top comments (0)