Skip to content

Zero Trust & API Access

What Is Cloudflare Zero Trust

The arc subdomains (internal API) are protected by Cloudflare Zero Trust Access. It sits in front of the origin server at the Cloudflare edge — every request is validated before it reaches the backend. Requests without valid credentials are rejected with 403 Forbidden and never reach the origin.

This is not just obscurity (a hard-to-guess URL). Zero Trust actively rejects all unauthorised traffic at the network level.

Service Tokens

Access to the API uses Service Tokens — machine-to-machine credentials generated in Cloudflare → Zero Trust → Access → Service Auth.

Each token consists of two values:

  • Client ID — stored as VITE_CF_ACCESS_CLIENT_ID
  • Client Secret — stored as VITE_CF_ACCESS_CLIENT_SECRET

A separate token exists per environment:

EnvironmentProtectsToken Stored In
Stagingstaging-arc.semalink.africaGitHub Environment staging
Testtest-arc.semalink.africaGitHub Environment test
Productionarc.semalink.africaGitHub Environment prod

How the Frontend Authenticates

The two token values are baked into the app bundle at build time. The Axios HTTP client attaches them as headers on every API request:

ts
// src/core/api/client.ts
import axios from 'axios'

const client = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  headers: {
    'CF-Access-Client-Id':     import.meta.env.VITE_CF_ACCESS_CLIENT_ID,
    'CF-Access-Client-Secret': import.meta.env.VITE_CF_ACCESS_CLIENT_SECRET,
  },
})

export default client

Cloudflare validates the headers at the edge on every request. If they match, the request is proxied to the origin. If they are missing or incorrect, Cloudflare returns 403.

Request Flow

Frontend App
    ↓  (HTTP request with CF-Access headers)
Cloudflare Edge
    ↓  Validates service token
    ├── Valid   → proxied to backend origin
    └── Invalid → 403 Forbidden (origin never contacted)

Rotating a Service Token

  1. Go to Cloudflare → Zero Trust → Access → Service Auth
  2. Select the token → Roll Credentials
  3. Copy the new Client ID and Client Secret
  4. Update VITE_CF_ACCESS_CLIENT_ID and VITE_CF_ACCESS_CLIENT_SECRET in the GitHub Environment
  5. Trigger a new deployment — the new token will be baked into the next build

Pending Setup

Access Application policies still need to be created for each arc subdomain in Cloudflare → Zero Trust → Access → Applications. Until these policies are in place, Zero Trust will not actively enforce the token check. See the post-setup checklist.

Internal use only — Sema Link Engineering