Quickstart
This takes you from an empty Cloudflare account to a deployed, Access-protected server you can sign in to. Allow about twenty minutes.
Before you begin
You need:
- A Cloudflare account with Workers, D1 and Zero Trust (Cloudflare Access).
- A hostname you control on that account. Access attaches to a hostname, not to a Worker.
- mise, which pins every tool this repository uses.
1. Clone and install
git clone https://github.com/yashau/prick && cd prickmise trustmise run bootstrapbootstrap installs the pnpm workspace from the lockfile and the git hooks.
wrangler comes with it, and every command below runs it through pnpm so you
get the pinned version.
2. Create the D1 database
pnpm --dir packages/app exec wrangler d1 create prickCopy the returned database_id into packages/app/wrangler.jsonc. The value
checked in is the placeholder 00000000-0000-0000-0000-000000000000, and a
deploy against it will not work. The id is not a secret.
3. Point the Worker at your hostname
wrangler.jsonc sets "workers_dev": false and "preview_urls": false, and CI
asserts both. That means the Worker has nowhere to go until you give it a route,
so uncomment and edit the routes block:
"routes": [ { "pattern": "prick.example.com", "custom_domain": true }],Leave workers.dev switched off
Cloudflare Access attaches to a hostname. A *.workers.dev hostname, or a
per-version preview URL, that Access is not in front of serves this Worker with
no authentication at all — every project, every environment, every reveal
endpoint, open to the internet.
Those two settings are what make the whole authorization model’s assumption true.
4. Generate and install the master key
openssl rand -base64 32pnpm --dir packages/app exec wrangler secret put MASTER_KEYMASTER_KEY must be base64 that decodes to exactly 32 bytes. It is
validated when the key ring is built, before any route runs, so a bad value
makes the Worker refuse every request — including /health — rather than
failing later on the first secret read.
Back this up now, before you store anything
There is no recovery path. A D1 export without MASTER_KEY is just ciphertext.
Read Backup and recovery before you continue.
5. Create the Access application
In the Cloudflare dashboard, under Zero Trust → Access → Applications, add a self-hosted application for the hostname from step 3, and add a policy for the people who should reach it.
From the application’s Overview tab, copy the Application Audience (AUD) tag — you need it in the next step.
6. Fill in the vars
Edit the vars block in packages/app/wrangler.jsonc:
"vars": { "ACCESS_TEAM": "your-team", "ACCESS_AUD": "<the AUD tag from step 5>", "BOOTSTRAP_ADMINS": "you@example.com", "REQUIRE_CTX_ACCESS": "false", "SECRET_MAX_BYTES": "65536", "ENV_MAX_SECRETS": "500", "BODY_MAX_BYTES": "1048576"}ACCESS_TEAM is the <team> in https://<team>.cloudflareaccess.com. It and
ACCESS_AUD are both asserted by the JWT verifier, and an empty ACCESS_AUD is
refused — a verifier that accepts tokens minted for a different Access
application is not a verifier.
BOOTSTRAP_ADMINS is how the first administrator comes to exist. Put your own
email there. See Access control.
Every var is described in Configuration.
7. Apply the database migrations
pnpm --dir packages/app exec wrangler d1 migrations apply prick --remoteMigrations are applied before the deploy, and they are additive only. That ordering is what makes “old code, new schema” the only state that exists in the window between the two steps.
8. Deploy
Check the resolved configuration first if you want to be careful:
pnpm --dir packages/app exec wrangler deploy --dry-runThen:
pnpm --dir packages/app exec wrangler deploy9. Verify that Access is actually in front of it
Do not skip this step. It is the one that catches the failure this whole design exists to prevent.
curl -i https://prick.example.com/api/v1/healthYou want Access to intercept this — a redirect to your Access login, or a 403.
A 200 here means your secrets manager is open to the internet
If that command returns 200 with a JSON body, Access is not protecting
this hostname. Stop and fix the Access application before storing anything.
When authenticated, the endpoint answers:
{ "service": "prick", "status": "ok", "version": "0.0.0-dev" }The version reads 0.0.0-dev for an in-tree build; releases stamp the real
value at build time.
10. Install the CLI
npm install -g @yashau/prickNot published yet
No release has been cut, so this package does not exist on npm today. Build the binary locally instead:
mise run build:rustIt lands at target/release/prk. See Install for
the full set of routes.
11. Sign in
prk login https://prick.example.comSigning in to https://prick.example.comSigned in to https://prick.example.comprk login probes /api/v1/health, discovers the authorization server,
registers a client for a loopback redirect, runs the PKCE handshake in your
browser, and stores the resulting token in a file only you can read. The whole
handshake — and the service-token path CI uses instead — is described in
Authentication.
Then confirm the server agrees about who you are:
prk whoamiyou@example.com (user)role: admin (global)If BOOTSTRAP_ADMINS names your address, that first authenticated request also
converts the implicit admin into a real, revocable grant.
12. Check everything at once
prk doctorok server url https://prick.example.com (from the stored login)ok token storage /home/you/.config/prick/credentials.json is owner-onlyok api /api/v1/health answered, version 0.0.0-devok access Cloudflare Access with managed OAuth is in front of this serverok identity you@example.com (user)ok installation running as a native binarySix ok lines means you are done. Any FAIL is explained in
Exit codes and errors.
Store your first secret
prk projects create "API service" --slug apiCreated project `API service` (api).prk env create Production --slug production --project apiCreated environment `Production` (production).prk secrets set DATABASE_URL --project api --env productionValue for DATABASE_URL:Added `DATABASE_URL` (rev 1).prk run --project api --env production -- printenv DATABASE_URLNext steps
- Onboard a new service — the full version of what you just started.
- Authentication — get CI authenticated too.
- Access control — convert
BOOTSTRAP_ADMINSinto real grants. - Backup and recovery — do this before you depend on it.