bao

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:

  1. Provision a D1 database and KV namespace (first run only)
  2. Validate and apply your bao.config.json
  3. Run database migrations
  4. Deploy the auth worker and rotation worker
  5. 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 baoRun workflow.