Getting Started
From zero to a first policy-resolved crypto operation — in Java and .NET.
المتطلبات المسبقة
- A DuoKey Cockpit tenant on the Enterprise or Free Trial edition (the cap.enabled feature).
- JDK 17+ (Java) or .NET 6+ (.NET).
- For the one-time policy/key setup: a Cockpit administrator session (see the two access models below).
Two access models
CAP has two planes, and they authenticate differently. Use the right one for the right job.
| Plane | Who uses it | Auth | Endpoints |
|---|---|---|---|
| Control plane | Security / platform team (once) | A Cockpit session (JWT) with the Cap.* permissions | /api/cap/policies, /api/cap/policies/from-template, /api/cap/policy-templates, /api/cap/simulate, /api/cap/drift, /api/cap/sdk/keys |
| Data plane (SDK) | Your application (every request) | A CAP API key dke_cap_… | /api/cap/sdk/resolve, /api/cap/sdk/observe |
The dke_cap_… key is accepted only on the data-plane /api/cap/sdk/* routes.
Policy and template management use a Cockpit session with Cap.Policies.Manage.
Step 1 — Bootstrap a tenant policy
The security team starts from a built-in compliance template instead of authoring
rules by hand. This is a control-plane call (Cockpit session, Cap.Policies.Manage):
curl -X POST "https://cockpit.example.com/api/cap/policies/from-template" \
-H "Authorization: Bearer $COCKPIT_SESSION_JWT" \
-H "Content-Type: application/json" \
-d '{ "template_key": "pci_dss_4", "name": "PCI baseline" }'Templates: pci_dss_4, finma_ch, enisa_eu, cnsa_2_0, fips_fedramp,
gdpr_pii (list them with GET /api/cap/policy-templates). See
Intents & Policies for what each one maps to.
CAP resolves against your tenant's active policy — the newest enabled policy
(highest version), unless a request pins a specific policy_id. There is no
in-place edit: to change rules, create a new (higher-version) policy.
Step 2 — Mint an SDK key
Your application authenticates with a CAP API key (control-plane call,
Cap.Sdk.Manage). The plaintext is shown once — store it in your secret manager.
curl -X POST "https://cockpit.example.com/api/cap/sdk/keys" \
-H "Authorization: Bearer $COCKPIT_SESSION_JWT" \
-H "Content-Type: application/json" \
-d '{ "name": "payments-svc" }'
# → { "id": "...", "key": "dke_cap_ab12cd34_<48 random chars>", ... }Inject it from your secret store or an environment variable (e.g. CAP_KEY). Never
commit a dke_cap_… key to the repository.
Step 3 — Get the reference client
CAP ships thin reference clients you download from your Cockpit and drop into your
project. The download endpoint returns a JSON envelope (language, filename,
content), so extract the content field — for example with jq — rather than
saving the response body directly:
# Java
curl -H "Authorization: Bearer $COCKPIT_SESSION_JWT" \
"https://cockpit.example.com/api/cap/sdk/download/java" \
| jq -r '.content' > CapClient.java
# .NET
curl -H "Authorization: Bearer $COCKPIT_SESSION_JWT" \
"https://cockpit.example.com/api/cap/sdk/download/dotnet" \
| jq -r '.content' > CapClient.csReference clients are also available for node, python, go, php and cobol.
Step 4 — First resolve + observe
resolve the intent
Ask CAP what to run for a data class + purpose. It returns an algorithm, a post-quantum posture, a key reference and a backend class.
run the operation
Perform the operation with the resolved algorithm and the policy-referenced key.
observe what ran
Report the algorithm that actually executed so CAP can detect drift.
Java
import ch.duokey.cap.CapClient;
import ch.duokey.cap.CapClient.CapDecision;
var cap = new CapClient("https://cockpit.example.com/api", System.getenv("CAP_KEY"));
CapDecision d = cap.resolve("pii", "sign");
System.out.println(d.algorithm()); // hybrid-ml-dsa65-ecdsa-p256
System.out.println(d.posture()); // hybrid
System.out.println(d.quantumResistant()); // true
System.out.println(d.backend()); // pqc_capable
// ... run the signature with d.algorithm() using the policy-referenced key ...
cap.observe("pii", "sign", "ecdsa-p256", "payments-svc");.NET
using DuoKey.Cap;
var cap = new CapClient("https://cockpit.example.com/api", Environment.GetEnvironmentVariable("CAP_KEY"));
CapDecision d = await cap.ResolveAsync("pii", "sign");
Console.WriteLine(d.Algorithm); // hybrid-ml-dsa65-ecdsa-p256
Console.WriteLine(d.Posture); // hybrid
Console.WriteLine(d.QuantumResistant); // True
Console.WriteLine(d.Backend); // pqc_capable
// ... run the signature with d.Algorithm using the policy-referenced key ...
await cap.ObserveAsync("pii", "sign", "ecdsa-p256", "payments-svc");When the security team raises the policy to post-quantum-only, this code does not
change — the next resolve(...) simply returns ml-dsa65.