Securing Your GraphQL API with Auth0 Machine-to-Machine Tokens and GitHub Automation

By
Learn how to enhance security for your GraphQL API using machine-to-machine tokens from Auth0. Automate token refresh through GitHub Actions, ensuring ongoing protection for your projects' valuable information.

In Composabase, we recently encountered an interesting challenge: How can we update the build information when our project provider triggers a webhook? Since the Auth0 system protects our interactions with our GraphQL, and no user is involved in this process, we lacked the Auth0 token necessary for authentication. In this blog post, we will share the solution we discovered: generating an Auth0 machine to machine token through a cronjob and storing it as a GitHub secret. Following the steps outlined here, you’ll see how easy it is to address this issue and enable Machine-to-Machine communication with Composabase.

Step 1: Creating a GitHub Action

We utilize GitHub Actions as our Continuous Integration/Continuous Delivery platform to initiate the update process.Start by creating a new YAML action file inside the .github/workflows folder of your project.
We define the name of the action as “Update M2M token” and specify the execution schedule using the cron format. Here, we set it to run every 12 hours, so our yaml will start with:

1 2 3 4 5 name: Update M2M token on: schedule: - cron: ‘0 0,12 * * *’ …

Step 2: Updating the GitHub Secret

Next, we need to update the secret within the GitHub repository. This involves executing a series of steps within a job.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 … jobs: update_secret: runs-on: ubuntu-latest steps: - run: npm install libsodium-wrappers - name: Update Secret uses: actions/github-script@v6 env: AUTH0_CLIENT_ID: ${{ secrets.AUTH0_M2M_CLIENT_ID }} AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_M2M_CLIENT_SECRET }} with: github-token: ${{ secrets.GRAPHAVIDER_ACCESS_TOKEN }} script: |    // The executed script…

In the update_secret job, we first install the libsodium-wrappers package and then use the actions/github-script@v6 action to interact with the GitHub API. The environment variables AUTH0_CLIENT_ID and AUTH0_CLIENT_SECRET are set using the secrets stored in GitHub. The subsequent script fetches a new token from Auth0 using the provided client ID and secret.

Step 3: Encrypting the Token

To interact with the GitHub API, we need to encrypt the token. This requires obtaining the repository’s public key and using the libsodium-wrappers library.

1 2 3 4 5 6 7 8 9 10 11 12 13 const sodium = require(‘libsodium-wrappers’) const tokenData = await fetch(“OUR_AUTH0_URL/oauth/token”, { method: “POST”, headers: { “Content-Type”: “application/json”, }, body: JSON.stringify({ “client_id”: process.env.AUTH0_CLIENT_ID, “client_secret”: process.env.AUTH0_CLIENT_SECRET, “audience”: process.env.OUR_AUTH0_AUDIENCE, “grant_type”: “client_credentials” }) })

This is the start of our script and is basically to ask auth0 for a new token based on the Client ID and Client Secret that we set from the secrets in the previous part and returns the following information.
const { access_token: token } = await tokenData.json();
Now we want to get the public key of our repository to interact with the secrets within the API.

Step 4: Get the Public Key

1 2 3 4 5 6 7 const { data: { key, key_id } } = await github.request(‘GET /repos/REPO_OWNER/REPOSITORY_NAME/actions/secrets/public-key’, { owner: ‘REPO_OWNER’, repo: ‘REPOSITORY_NAME’, headers: { ‘X-GitHub-Api-Version’: ‘2022-11-28’ }, })

This allows us to have the needed information to encrypt the token because Github needs the values encrypted to be stored as secrets. That’s why we installed the libsodium-wrappers library.

Step 5: Token Encrypted

1 2 3 4 5 6 const encrypted_value = await sodium.ready.then(() => { let binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL) let binsec = sodium.from_string(token) let encBytes = sodium.crypto_box_seal(binsec, binkey) return output = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL) });

After that, we need to set the new value of the Machine-to-Machine token in our repository to interact with the database in our webhooks!

Step 6: Update the Secret

1 2 3 4 5 6 7 8 9 10 const result = await github.request(‘PUT /repos/REPO_OWNER/REPOSITORY_NAME/actions/secrets/MACHINE_TO_MACHINE_TOKEN’, { owner: ‘REPO_OWNER’, repo: ‘REPOSITORY_NAME’, secret_name: ‘MACHINE_TO_MACHINE_TOKEN’, encrypted_value, key_id, headers: { ‘X-GitHub-Api-Version’: ‘2022-11-28’ } })

Finally, we only need to call our deploy process of the application to have the new value in the running application.

1 2 3 4 call_deploy: needs: update_secret uses: REPO_OWNER/REPOSITORY_NAME/.github/workflows/deploy.yml@main secrets: inherit

Wrapping Up:

By following the steps outlined in this blog post, you can effectively update the build information in Composabase by generating an Auth0 token through a cronjob and storing it as a GitHub secret. This solution ensures secure and efficient Machine-to-Machine communication. With the power of GitHub Actions and Auth0 integration, you can streamline your development process and maintain the authentication mechanisms for your projects.

Learn everything about GraphQL and the state of modern API integration (2024) in one of our most comprehensive guides on the topic here. 
 

Share with others

Try Composabase Now!

Find how to improve your DX by leveraging the true potential of GraphQL.