This guide walks you through the first validation from an empty state to a verifiable, countersigned WAF++ PASS certificate.
There is no user account to create. Access to the validation service is managed through API tokens, which will soon be available for purchase on the Shop page.
What you need
Before you start, make sure you have:
- A WAF++ PASS run produced by the
wafpassCLI (wafpass check --output json). - A
wafpass-serverinstance that can receive the run and attest it with its own Ed25519 key. - An API token to authenticate submissions to the gateway. (Purchase flow coming soon — the Shop will be enabled shortly.)
The gateway itself never sees your private keys. It only verifies public keys, certificates, and signatures.
The validation process
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. Run WAF++ checks locally │
│ wafpass check ./infra --output json │
│ │ │
│ ▼ │
│ 2. Sign the run locally with your organisation Ed25519 key │
│ → local attestation (public key + signature) │
│ │ │
│ ▼ │
│ 3. Send the run to your wafpass-server │
│ Server verifies the local attestation │
│ Server signs the canonical run hash with its Ed25519 key │
│ │ │
│ ▼ │
│ 4. Server submits to the WAF++ validation gateway │
│ Gateway verifies the server sub-CA certificate │
│ Gateway verifies both attestations │
│ Gateway countersigns the validation │
│ │ │
│ ▼ │
│ 5. You receive a validation ID, badge, and permanent verify URL │
└─────────────────────────────────────────────────────────────────────────────┘
Verify a server certificate from the browser
If you already have a gateway-issued server certificate, you can verify it independently of any backend:
- Open the Server Cert page.
- Paste the PEM content of
server.crtinto the form. - Click Verify certificate.
The page calls the public, unauthenticated endpoint
POST /api/v1/validations/server/verify and shows:
| Field | Meaning |
|---|---|
valid |
Cryptographically signed by the gateway root CA and still within its validity window. |
registered |
The gateway database knows this server certificate. |
revoked |
Whether the certificate has been revoked by an administrator. |
fingerprint_sha256 |
SHA-256 fingerprint of the certificate for audit logs. |
The same endpoint can be used from CI or the command line:
curl -X POST https://waf.lew-app.de/api/v1/validations/server/verify \
-H "Content-Type: application/json" \
-d '{"server_certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"}'
Step 1 — Obtain an API token
API tokens are not tied to a user account. Each token is a prepaid credit
bundle that lets a wafpass-server submit validation runs to the gateway.
Coming soon: the Shop page will let you buy tokens directly. Until then, contact the gateway operator to receive an initial token.
A token looks like this:
wafpass_abcdefghijklmnopqrstuvwxyz0123456789ABCD
Keep it secret. It is shown only once when created.
Step 2 — Register your wafpass-server
Your server needs a sub-CA certificate issued by the gateway. A gateway administrator creates it in the Admin UI:
- Log in to the admin UI.
- Open the Server Certificates panel.
- Enter a unique
server_idand paste the server’s Ed25519 public key or certificate. - Click Issue certificate.
The gateway returns a PEM certificate chain. Store the certificate on the server
as server.crt. The matching private key (server.key) never leaves the server.
Step 3 — Run the WAF++ checks
From your local development or CI environment:
wafpass check ./infra \
--output json \
--project my-project \
--branch main
This produces a run JSON file containing every control check and its status.
Step 4 — Sign locally
Your organisation key signs the canonical hash of the run JSON. This proves that the run came from your environment and has not been modified since.
from hashlib import sha256
import canonicaljson
canonical_hash = sha256(canonicaljson.dumps(run).encode("utf-8")).hexdigest()
signature = ed25519_sign(canonical_hash, org_private_key)
The server receives the run, the public key, and the signature as the local attestation bundle.
Step 5 — Server attestation and submission
The wafpass-server:
- Verifies the local attestation against the run JSON.
- Signs the canonical hash with its own Ed25519 attestation key.
- POSTs the bundle to the gateway:
curl -X POST https://waf.lew-app.de/api/v1/validations \
-H "Content-Type: application/json" \
-H "X-Api-Key: wafpass_..." \
-d @submit-payload.json
The request body contains:
| Field | What it is |
|---|---|
server_certificate |
The gateway-issued sub-CA certificate for this server. |
local_attestation |
The organisation’s public key, signature, and optional certificate. |
run |
The canonical WAF++ PASS run JSON. |
See the full edge-to-edge example for a complete, copy-pasteable payload.
Step 6 — Receive the official validation
On success the gateway returns 201 Created:
{
"validation_id": "waf-ex-12345678-1234-1234-1234-123456789abc",
"status": "official",
"canonical_hash": "7184231525be8173ccb7eb0b5fc804630e37c49c2ec3c511b3c47b8d875a54a6",
"server_signature": "...",
"gateway_signature": "...",
"certificate_chain": ["-----BEGIN CERTIFICATE-----\n..."],
"badge_url": "https://waf.lew-app.de/api/v1/validations/waf-ex-12345678-.../badge.svg",
"verify_url": "https://waf.lew-app.de/api/v1/validations/waf-ex-12345678-.../verify",
"certificate_url": "https://waf.lew-app.de/api/v1/validations/waf-ex-12345678-.../certificate.pdf"
}
Share the verify_url or embed the badge_url in documentation, pull requests,
or compliance reports. Anyone can verify it without trusting your server.
Step 7 — Verify publicly
Anyone can check the current status:
curl https://waf.lew-app.de/api/v1/validations/waf-ex-12345678-1234-1234-1234-123456789abc/verify
The gateway walks the certificate chain, checks the signatures, and reports
valid or revoked.
Next steps
- See a concrete request/response in the full example.
- Read the trust model details on the About page.
- Inspect the public root certificate at /api/v1/validations/root.crt.
- Buy API tokens on the Shop once it is live.