Deploying changes to your Auth0 accounts with GitHub Actions
Sandrino Di Mattia / November 12, 2020
7 min read • ––– views
Introduction#
As you build applications which use Auth0 it's a best practice to create a dedicated account per environment. This allows you to isolate your production userbase from your other environments and you'll also be able to configure different administrators per environment (eg: engineers might not have access to the production environment).
But managing multiple environments does come at a cost and you'll want to avoid manual changes to keep environments up-to-date. In this article we'll explore how the Auth0 Deploy CLI can be used to export the configuration of your environment and then import this same configuration on your other environments. The configuration will be managed in GitHub and will be deployed to the environments using GitHub Actions.
This is how the final setup will look like once we're done:
Configuring your Auth0 accounts#
In this scenario we'll have 3 different Auth0 accounts:
- zerohr-dev.auth0.com: The account used by developers. This is where manual changes are happening.
- zerohr-staging.auth0.com: The account used by the Product Managers and QA team.
- zerohr-prod.auth0.com: The account used by end users/customers.
For each of these accounts we'll need to create a Machine to Machine client which represents the Auth0 Deploy CLI. It will need the client_id
and client_secret
to get access to the Management API.
When creating the client we'll also need to enable it for the Management API and enable all of the scopes:
And that's all there is to it. As a next step we can start by creating whatever resource that is needed in the development account. In this example I've created an API, some a clients, a rule ...
Initial Export#
Once the development account is configured we can use the Auth0 Deploy CLI to perform an initial export. Let's start by creating a config file which contains the client_id
and client_secret
for the M2M client in the development account. We can also use the EXCLUDED_PROPS
setting to avoid exporting any secrets:
{
"AUTH0_DOMAIN": "zerohr-dev.us.auth0.com",
"AUTH0_CLIENT_ID": "qOY47ME3LaPWkYOwQj8o62lVUNiUKw01",
"AUTH0_CLIENT_SECRET": "...",
"EXCLUDED_PROPS": {
"clients": ["client_secret"],
"connections": ["options.client_secret"]
}
}
And now to run the export:
npm i -g auth0-deploy-cli
a0deploy export -c config.json --strip --format yaml --output_folder .
This command will go over all of the resources in our Auth0 account and export them to a yaml
file (+ some files for any rule/hook/... in the account).
The following is excerpt of what such an export looks like:
rules:
- name: custom-claims
script: ./rules/custom-claims.js
stage: login_success
enabled: true
order: 1
resourceServers:
- name: ZeroHR API
identifier: 'https://api.dev.zerohr.app/'
allow_offline_access: false
signing_alg: RS256
skip_consent_for_verifiable_first_party_clients: true
token_lifetime: 86400
token_lifetime_for_web: 7200
Moving to GitHub#
A sample repository with the workflows and a sample export can be found here.
We now have everything we need to create a GitHub repository containing the following:
- The configuration for dev/staging/production
- The yaml file and the other files (*.js files for all of your rules and hooks)
- The GitHub Action workflows
Let's start by creating a local directory for the repository and move all of the exported files in it:
mkdir github-actions-auth0-deploy
git init
We'll also create a dedicated config
folder containing all of the configuration files:
./config/dev.json
./config/prod.json
./config/staging.json
Each of these configuration files will contain the domain and the client_id
. Note that the client_secret
should not be added here. We'll manage that using GitHub Secrets, not directly in source control.
{
"AUTH0_DOMAIN": "zerohr-staging.us.auth0.com",
"AUTH0_CLIENT_ID": "Y13eh0EhojdF1Bti06FLJJ1jZx0Pb0hJ",
"AUTH0_ALLOW_DELETE": true,
"AUTH0_KEYWORD_REPLACE_MAPPINGS": {
"APP_CALLBACKS": ["https://www.staging.zerohr.app", "https://staging.zerohr.app"],
"API_IDENTIFIER": "https://api.staging.zerohr.app/"
},
"EXCLUDED_PROPS": {
"clients": ["client_secret"],
"connections": ["options.client_secret"]
}
}
You'll also notice the AUTH0_KEYWORD_REPLACE_MAPPINGS
which allows us to have environment specific settings which will be injected in the yaml
file. A use case here is that the applications in your environments have different URLs, and these URLs can be managed here and then injected in the template as we deploy to a specific environment.
For this to work we do need to modify the yaml
file and replace the actual values of the URLs with variables. The ##var##
format will be replaced with a string literal, the @@var@@
format with a JSON representation of the variable (in this case an actual array).
resourceServers:
- name: ZeroHR API
identifier: '##API_IDENTIFIER##'
allow_offline_access: false
signing_alg: RS256
skip_consent_for_verifiable_first_party_clients: true
token_lifetime: 86400
token_lifetime_for_web: 7200
clients:
- name: ZeroHR App
app_type: spa
callbacks: @@APP_CALLBACKS@@
client_aliases: []
cross_origin_auth: false
custom_login_page_on: true
grant_types:
- authorization_code
- refresh_token
is_first_party: true
GitHub Actions & Continuous Delivery#
As a final step we'll create 2 workflows:
.github/workflows/auth0-staging.yml
which will deploy to staging when we push a change to thestaging
branch.github/workflows/auth0-prod.yml
which will deploy to production when we merge a change to themain
branch
GitHub recently decided to use main
as the name of the default branch instead of master
. If you still have a repository which uses master
you'll need to change the workflow below.
The workflows are very simply, they just install and run the Auth0 Deploy CLI:
name: Deploy to Auth0 production account
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Download files from the current repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x'
- name: Install the auth0-deploy-cli
run: npm install
- name: Import changes to the Auth0 production account
env:
AUTH0_CLIENT_SECRET: ${{ secrets.PROD_AUTH0_CLIENT_SECRET }}
run: npm run import:prod
To make local testing easier we can move all of the commands to a package.json
file:
"scripts": {
"export:dev": "a0deploy export --strip --format yaml --output_folder . --config_file ./config/dev.json --secret $DEV_AUTH0_CLIENT_SECRET",
"import:staging": "a0deploy import --input_file tenant.yaml --config_file ./config/staging.json",
"import:prod": "a0deploy import --input_file tenant.yaml --config_file ./config/prod.json"
}
This is why you'll see that the final line of the workflow uses npm run import:prod
.
The Auth0 Deploy CLI will need to use the client_id
and client_secret
for the given environment to access the Management API, which is used to create/update/delete resources. The client_secret
is a secret and should not be stored in source control. So for each environment we'll create a Repository Secret in GitHub:
When the import step runs as part of the job it will load the secret and expose it as an environment variable to the Auth0 Deploy CLI:
- name: Import changes to the Auth0 production account
env:
AUTH0_CLIENT_SECRET: ${{ secrets.PROD_AUTH0_CLIENT_SECRET }}
run: npm run import:prod
Deployment#
The jobs will run whenever there is a push to the main
or staging
branch. As a simple test we can just modify a setting one one of our APIs (Resource Server) and push the change to the staging
branch.
git checkout -b staging
git add tenant.yaml
git commit -m "Changed token lifetime for the main API"
git push -u origin staging
Immediately after pushing the change we can see that a new workflow is started:
By opening the workflow you to inspect every step of the job. If the job fails you'll find the reason in the Import changes to the Auth0 account step:
Next Steps#
If any other changes need to happen to your Auth0 environments we can make the manually in the development account and then perform a new export:
DEV_AUTH0_CLIENT_SECRET=... npm run export:dev
Running the export will then make changes to your tenant.yaml
file which can be reviewed in your IDE. This will allow us to pick the changes we need to commit but it's also an opportunity to replace environment specific values (like https://api.zerohr.app
) with a variable defined in AUTH0_KEYWORD_REPLACE_MAPPINGS
.
✅ Success!#
And we're done. We've put a process in place where changes can be automated across different Auth0 accounts and which leverages all of the benefits that GitHub offers: an audit trail, PR reviews, protected branches, access control, ...
This solution can also be applied to GitLab CI/CD, Bitbucket Pipelines, Azure DevOps, Jenkins, ...