Skip to content

Secrets Reference

Each of the three GitHub Environments (staging, test, prod) holds these 6 secrets:

SecretDescriptionWhere to Regenerate
VITE_API_BASE_URLAPI base URL for the environmentChange only if subdomain changes
VITE_CF_ACCESS_CLIENT_IDCF Access service token Client IDCloudflare → Zero Trust → Access → Service Auth → roll credentials
VITE_CF_ACCESS_CLIENT_SECRETCF Access service token Client SecretSame as above — ID and Secret roll together
CLOUDFLARE_API_TOKENCF API token with Pages write permissionCloudflare → My Profile → API Tokens
CLOUDFLARE_ACCOUNT_IDCloudflare account ID (a9e39304...)Cloudflare Dashboard sidebar — does not change
SLACK_WEBHOOK_URLSlack Incoming Webhook URLSlack → api.slack.com/apps → Incoming Webhooks

The admin portal has a single staging GitHub Environment. Production environment is not yet set up.

SecretDescription
VITE_API_BASE_URLhttps://staging-arc.semalink.africa for staging
CLOUDFLARE_API_TOKENCF API token with Pages write permission
CLOUDFLARE_ACCOUNT_IDa9e39304b10e79b6b6e7c73a128b8ce7
SLACK_WEBHOOK_URLSlack Incoming Webhook URL (same webhook as frontend)

The API deploy workflow SSHes into the DigitalOcean droplet. All secrets live in the staging GitHub Environment on the semalink-api repo.

SecretDescription
DATABASE_URLNeon staging pooler URL (ep-...-pooler...neon.tech/neondb?sslmode=require)
REDIS_URLUpstash staging Redis (rediss://default:...@...upstash.io:6379)
RABBITMQ_PASSRabbitMQ password — 32+ random chars; see rotation runbook in api-ops.md
JWT_SECRET64+ char random secret for customer access tokens
JWT_REFRESH_SECRET64+ char random secret for customer refresh tokens
ADMIN_JWT_SECRET64+ char random secret for admin staff tokens (separate namespace)
MAILGUN_API_KEYMailgun API key for transactional email
MAILGUN_DOMAINmailer.semalink.africa
MAILGUN_FROMnoreply@mailer.semalink.africa
CELCOM_API_URLCelcom Africa SMS gateway base URL
CELCOM_API_KEYCelcom Africa API key
R2_ACCOUNT_IDCloudflare account ID for R2
R2_BUCKET_NAMEstaging
R2_PUBLIC_URLPublic r2.dev URL for the staging bucket
R2_ACCESS_KEY_IDR2 access key ID
R2_SECRET_ACCESS_KEYR2 secret access key
STAGING_DROPLET_IP209.38.197.79
STAGING_SSH_KEYED25519 private key for the deploy user on the droplet
SLACK_WEBHOOK_URLSlack Incoming Webhook URL for deploy notifications

How to Rotate a Secret

  1. Generate the new credential from the source system first
  2. Go to GitHub → Sema-Link/semalink-frontend → Settings → Environments → [environment]
  3. Find the secret and click Edit
  4. Paste the new value and save
  5. Trigger a new deployment — the next build will use the new secret automatically

Checklist

Completed ✅

  • GitHub Environments created (staging, test, prod)
  • All 6 secrets set in each environment (18 total)
  • Cloudflare Pages projects created and custom domains attached
  • production_branch: main set on all three app projects
  • Cloudflare Zero Trust enabled
  • Service tokens created for all three environments
  • Service token credentials stored in GitHub secrets
  • Slack notifications working on success and failure
  • All three environments live and deploying

Pending ⚠️

  • Create Cloudflare Access Application policies for arc, staging-arc, and test-arc subdomains in Cloudflare → Zero Trust → Access → Applications. Service tokens exist but are not yet enforced — the API is not actively protected until these policies are created.
  • Wire CF Access headers into the Axios client in src/core/api/ (see Zero Trust)

Internal use only — Sema Link Engineering