Authentication
The three VeilBrowser credentials, where each one belongs, and how to manage organization API keys.
VeilBrowser uses three distinct credentials. Mixing them up is the most common integration mistake, so start here before writing any client code.
The three credentials
| Credential | Header / transport | Issued by | Authorizes |
|---|---|---|---|
| Dashboard session | Cookie or Authorization: Bearer | Signing in at veilbrowser.net | Profile CRUD, session history, organizations, billing |
| Organization API key | X-API-Key | Dashboard → Settings → API keys | Worker-to-cloud calls: license authorize, profile config, session tracking, release catalog |
| Worker API key | X-API-Key | You, as the worker's API_KEY env var | Inbound requests to a Local API worker |
The first two go to api.veilbrowser.net. The third goes to a worker on your own
network. They are never interchangeable.
Dashboard session
Profile management is a dashboard operation. GET/POST/PATCH/DELETE /v1/profiles,
GET /v1/sessions, the organization endpoints and everything under /v1/billing
require a signed-in session, established by Better Auth at sign-in.
Scripts that manage profiles carry the same session cookie a browser would:
curl https://api.veilbrowser.net/v1/profiles \
-H "Cookie: better-auth.session_token=..."Organization keys are not a substitute here
An organization API key will not authenticate profile CRUD. It is scoped to the worker integration endpoints listed below. If you need unattended profile provisioning, drive it from a service account session.
Organization API key
This is the key every self-hosted deployment depends on. It identifies the organization, authorizes the private image pull, and gates each browser launch at runtime.
Creating one
Open the dashboard
Sign in and go to Settings → API keys.
Create the key
Give it a name that identifies where it will run, such as prod-cluster-eu. Keys are
scoped to the organization that is active when you create them, so confirm the right
organization is selected first.
Copy it immediately
The full key is shown once. VeilBrowser stores only a SHA-256 hash, so a lost key cannot be recovered — it can only be revoked and replaced.
The Connect page shows the same key alongside its lowercased form, which is the path segment used when pulling images from the license-gated registry.
Where it is used
| Purpose | How it travels |
|---|---|
| Image pull | Lowercased, as a path segment: registry.veilbrowser.net/<org-key-lower>/local-api |
| Worker runtime | The VEIL_KEY environment variable on each worker |
| Cluster-mode launch | Inside the env payload of the wss://<host>/launch query string |
Endpoints that accept it:
POST /v1/license/authorize— concurrency check before a launchGET /v1/profiles/:id/config— fetch a profile's launch configurationPOST /v1/profiles/:id/sessionsandDELETE /v1/profiles/:id/sessions/:sessionId— session lifecycleGET /v1/chromium/releasesandGET /v1/chromium/releases/:version/download— browser build catalog
Rotating
Because the key is both a pull credential and a runtime credential, rotate in this order to avoid an outage:
Create the replacement
Add a second key before disabling anything. Both keys are valid at once.
Roll the fleet
Update VEIL_KEY in each worker's environment and restart. Workers fail closed, so a
worker still holding a revoked key stops launching rather than launching unlicensed.
Verify, then revoke
Confirm every worker is healthy and launching, then delete the old key from Settings → API keys.
Treat it like a password
An organization key grants image pulls and browser launches against your plan. Store it in your secret manager, never in a repository, and rotate it immediately if it leaks.
Worker API key
Each Local API worker is protected by its own shared secret, set as API_KEY in the
worker's environment and sent by clients as X-API-Key. It has nothing to do with your
VeilBrowser account — it exists so that only your automation can reach the worker.
curl -X POST http://localhost:3000/sessions/profile \
-H "X-API-Key: $WORKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "profileId": "<profile-uuid>" }'Cluster mode bypasses this header
When a worker runs with VEIL_SERVER_MODE=cluster, the /launch WebSocket and the
/browsers/* routes do not check X-API-Key — authorization happens per launch using
the organization key in the connection payload. Never expose a cluster-mode worker
directly to the internet; put it behind the cluster-manager edge. See
Edge security & TLS.
Next steps
- API reference — which endpoint takes which credential.
- Errors — what an authentication failure looks like.
- Licensing & concurrency — what the organization key authorizes at launch.