Deploy workflow
Add the bao GitHub Actions workflow to your repository to automatically deploy your auth service on every push.
The bao deploy action provisions your Cloudflare infrastructure and deploys the auth service on every push. Add this workflow file to your repository once and deployments happen automatically.
Before you start
You need a Cloudflare API token and your GitHub secrets configured. Set those up first →
Create the workflow file
Create .github/workflows/deploy.yml in your repository:
name: Deploy bao
on:
push:
branches:
- main
workflow_dispatch:
inputs:
force_rotate:
description: "Regenerate auth secrets from scratch (logs all users out)"
required: false
default: "false"
type: choice
options:
- "false"
- "true"
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Deploy bao
uses: getbao/bao@v1
with:
environment: production
api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}
license_key: ${{ secrets.GETBAO_LICENSE_KEY }}
force_rotate: ${{ inputs.force_rotate || 'false' }}Add your license key
The action downloads the worker bundle from getbao on every run. Add your license key as a repository secret named GETBAO_LICENSE_KEY.
Pass OAuth credentials (if using social login)
If you have GitHub or Google social login enabled in bao.config.json, pass the credentials via app_secrets:
- name: Deploy bao
uses: getbao/bao@v1
with:
environment: production
api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}
license_key: ${{ secrets.GETBAO_LICENSE_KEY }}
app_secrets: |
{
"GITHUB_CLIENT_ID": "${{ secrets.GITHUB_CLIENT_ID }}",
"GITHUB_CLIENT_SECRET": "${{ secrets.GITHUB_CLIENT_SECRET }}",
"GOOGLE_CLIENT_ID": "${{ secrets.GOOGLE_CLIENT_ID }}",
"GOOGLE_CLIENT_SECRET": "${{ secrets.GOOGLE_CLIENT_SECRET }}"
}Only include the keys for providers you have enabled.
Push to deploy
Commit the workflow file and push to main. The action will:
- Provision a D1 database and KV namespace (first run only)
- Validate and apply your
bao.config.json - Run database migrations
- Deploy the auth worker and rotation worker
- Bootstrap an encrypted auth secret (first run only)
The deployed worker URL is printed in the Actions log and available as the deployment_url output.
Multiple environments
To deploy to separate dev and production environments, duplicate the job and change the environment input:
jobs:
deploy-dev:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: getbao/bao@v1
with:
environment: dev
api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}
license_key: ${{ secrets.GETBAO_LICENSE_KEY }}
deploy-prod:
needs: deploy-dev
runs-on: ubuntu-latest
environment: production
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: getbao/bao@v1
with:
environment: production
api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}
license_key: ${{ secrets.GETBAO_LICENSE_KEY }}Each environment gets its own isolated workers, D1 database, and KV namespace.
CORS
Your app’s origin must be listed in bao.config.json under cors.origins, otherwise the browser will block requests from your frontend:
{
"cors": {
"origins": ["https://my-app.com", "http://localhost:3000"]
}
}Commit the change and push to main — the deploy workflow applies it automatically.
Force-rotating secrets
The force_rotate input discards all existing auth secret versions and generates a fresh one. This logs out all active users. Use it only if you believe your secrets have been compromised.
Trigger it manually from the Actions tab → Deploy bao → Run workflow.