Runtime Algorithm Discovery & PQC Smoke-Test

Query the catalogue of supported algorithms at runtime, filter PQC-only, and smoke-test the first result end-to-end. Useful for feature flags and tenant provisioning tooling.

🔍 Runtime Algorithm Discovery & PQC Smoke-Test

Scenario: discover the algorithms the platform supports at runtime (via GET /api/v3/algorithms), filter to post-quantum only, pick the first ENCRYPT_DECRYPT result and prove it works with a full round-trip. Useful for feature flags ("only offer PQC in the UI if it's really available") and for automated provisioning tooling.

Prerequisites

Same two identities as the AES-256 recipe.


Step-by-step

export BASE_URL="https://staging.ankatech.co"
export ADMIN_EMAIL="[email protected]" ADMIN_PASSWORD="••••••••••••"
export TENANT_ID="00000000-0000-0000-0000-000000000003"
export CLIENT_ID="00000000-0000-0000-0000-000000000000"
export CLIENT_SECRET="••••••••••••••••••••••••••••••••"

# Step 1: both tokens (see aes-256-basic for the full boilerplate)
export ADMIN_TOKEN=$(curl -s -X POST "$BASE_URL/api/v3/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=password" --data-urlencode "username=$ADMIN_EMAIL" \
  --data-urlencode "password=$ADMIN_PASSWORD" --data-urlencode "tenant_id=$TENANT_ID" \
  | jq -r .access_token)

export APP_TOKEN=$(curl -s -X POST "$BASE_URL/api/v3/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "client_id=$CLIENT_ID" --data-urlencode "client_secret=$CLIENT_SECRET" \
  | jq -r .access_token)

# Step 2: discover PQC algorithms (public endpoint, uses app token)
curl -s "$BASE_URL/api/v3/key-management/supported-algorithms?category=POST_QUANTUM&keyOps=encrypt,decrypt" \
  -H "Authorization: Bearer $APP_TOKEN" \
  | tee /tmp/algos.json | jq '.[] | {kty, alg, status, securityLevel}'

# Step 3: pick the first PQC KEM candidate
export PICK_KTY=$(jq -r '.[0].kty' /tmp/algos.json)     # e.g. "ML-KEM"
export PICK_ALG=$(jq -r '.[0].alg' /tmp/algos.json)     # e.g. "ML-KEM-768"
export KID="smoketest-$(date +%s)"
echo "Picked kty=$PICK_KTY  alg=$PICK_ALG  kid=$KID"

# Step 4: admin creates a key with the picked algorithm
curl -s -X POST "$BASE_URL/api/v3/admin/tenants/$TENANT_ID/keys" \
  -H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
  -d "{
    \"kid\":\"$KID\", \"kty\":\"$PICK_KTY\", \"algorithm\":\"$PICK_ALG\",
    \"purpose\":\"ENCRYPT_DECRYPT\", \"keyOps\":[\"encrypt\",\"decrypt\"]
  }" | jq

# Step 5: smoke test — encrypt / decrypt round-trip (app)
export DATA_B64=$(printf "%s" "PQC smoke test" | base64 -w0)
enc=$(curl -s -X POST "$BASE_URL/api/v3/crypto/encrypt" \
  -H "Authorization: Bearer $APP_TOKEN" -H "Content-Type: application/json" \
  -d "{ \"kid\":\"$KID\", \"data\":\"$DATA_B64\" }")
echo "Encrypted with: $(echo "$enc" | jq -r .algorithmUsed)"

dec=$(curl -s -X POST "$BASE_URL/api/v3/crypto/decrypt" \
  -H "Authorization: Bearer $APP_TOKEN" -H "Content-Type: application/json" \
  -d "{ \"jweToken\": $(echo "$enc" | jq .jweToken) }")
echo "Decrypted:      $(echo "$dec" | jq -r .decryptedData | base64 -d)"
echo "PQC smoke test PASSED"
import base64, requests, time

BASE = "https://staging.ankatech.co"
TENANT_ID = "00000000-0000-0000-0000-000000000003"

def tok(f): return requests.post(f"{BASE}/api/v3/auth/token", data=f).json()["access_token"]
admin = {"Authorization": f"Bearer {tok({'grant_type':'password','username':'[email protected]','password':'•••','tenant_id':TENANT_ID})}"}
app   = {"Authorization": f"Bearer {tok({'grant_type':'client_credentials','client_id':'…','client_secret':'…'})}"}

# Discover PQC algorithms
algos = requests.get(
    f"{BASE}/api/v3/key-management/supported-algorithms",
    params={"category": "POST_QUANTUM", "keyOps": "encrypt,decrypt"},
    headers=app,
).json()

# Pick the first candidate
pick = algos[0]
kid = f"smoketest-{int(time.time())}"
print(f"Picked kty={pick['kty']}  alg={pick['alg']}  kid={kid}")

# Admin creates the key
requests.post(f"{BASE}/api/v3/admin/tenants/{TENANT_ID}/keys", headers=admin, json={
    "kid": kid, "kty": pick["kty"], "algorithm": pick["alg"],
    "purpose": "ENCRYPT_DECRYPT", "keyOps": ["encrypt","decrypt"],
}).raise_for_status()

# Smoke test round-trip
data_b64 = base64.b64encode(b"PQC smoke test").decode()
enc = requests.post(f"{BASE}/api/v3/crypto/encrypt", headers=app,
                    json={"kid": kid, "data": data_b64}).json()
dec = requests.post(f"{BASE}/api/v3/crypto/decrypt", headers=app,
                    json={"jweToken": enc["jweToken"]}).json()

assert base64.b64decode(dec["decryptedData"]) == b"PQC smoke test"
print(f"PQC smoke test PASSED — algorithm={enc['algorithmUsed']}")
import java.net.URI;
import java.net.http.*;
import java.util.Base64;
import com.fasterxml.jackson.databind.*;

public class AlgorithmDiscovery {

    static final String BASE_URL       = "https://staging.ankatech.co";
    static final String ADMIN_EMAIL    = "[email protected]";
    static final String ADMIN_PASSWORD = "••••••••••••";
    static final String TENANT_ID      = "00000000-0000-0000-0000-000000000003";
    static final String CLIENT_ID      = "00000000-0000-0000-0000-000000000000";
    static final String CLIENT_SECRET  = "••••••••••••••••••••••••••••••••";

    static final HttpClient   http = HttpClient.newHttpClient();
    static final ObjectMapper json = new ObjectMapper();

    static String token(String body) throws Exception {
        var r = http.send(HttpRequest.newBuilder(URI.create(BASE_URL + "/api/v3/auth/token"))
            .header("Content-Type", "application/x-www-form-urlencoded")
            .POST(HttpRequest.BodyPublishers.ofString(body)).build(),
            HttpResponse.BodyHandlers.ofString());
        return json.readTree(r.body()).get("access_token").asText();
    }

    public static void main(String[] args) throws Exception {
        var adminAuth = "Bearer " + token("grant_type=password&username=" + ADMIN_EMAIL
            + "&password=" + ADMIN_PASSWORD + "&tenant_id=" + TENANT_ID);
        var appAuth   = "Bearer " + token("grant_type=client_credentials&client_id="
            + CLIENT_ID + "&client_secret=" + CLIENT_SECRET);

        // Discover PQC algorithms
        var algosResp = http.send(HttpRequest.newBuilder(URI.create(
            BASE_URL + "/api/v3/key-management/supported-algorithms"
            + "?category=POST_QUANTUM&keyOps=encrypt,decrypt"))
            .header("Authorization", appAuth).GET().build(),
            HttpResponse.BodyHandlers.ofString());
        JsonNode algos = json.readTree(algosResp.body());
        JsonNode pick  = algos.get(0);
        String   kid   = "smoketest-" + System.currentTimeMillis();
        System.out.println("Picked kty=" + pick.get("kty").asText()
            + " alg=" + pick.get("alg").asText() + " kid=" + kid);

        // Admin creates the key
        http.send(HttpRequest.newBuilder(URI.create(
            BASE_URL + "/api/v3/admin/tenants/" + TENANT_ID + "/keys"))
            .header("Authorization", adminAuth).header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(String.format(
                "{ \"kid\": \"%s\", \"kty\": \"%s\", \"algorithm\": \"%s\","
                + " \"purpose\": \"ENCRYPT_DECRYPT\", \"keyOps\": [\"encrypt\",\"decrypt\"] }",
                kid, pick.get("kty").asText(), pick.get("alg").asText()))).build(),
            HttpResponse.BodyHandlers.ofString());

        // Smoke test round-trip
        var dataB64 = Base64.getEncoder().encodeToString("PQC smoke test".getBytes());
        var encResp = http.send(HttpRequest.newBuilder(URI.create(BASE_URL + "/api/v3/crypto/encrypt"))
            .header("Authorization", appAuth).header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(
                "{ \"kid\": \"" + kid + "\", \"data\": \"" + dataB64 + "\" }")).build(),
            HttpResponse.BodyHandlers.ofString());
        JsonNode enc = json.readTree(encResp.body());

        var decResp = http.send(HttpRequest.newBuilder(URI.create(BASE_URL + "/api/v3/crypto/decrypt"))
            .header("Authorization", appAuth).header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(
                "{ \"jweToken\": " + enc.get("jweToken") + " }")).build(),
            HttpResponse.BodyHandlers.ofString());
        String plaintext = new String(Base64.getDecoder().decode(
            json.readTree(decResp.body()).get("decryptedData").asText()));
        if (!"PQC smoke test".equals(plaintext)) throw new RuntimeException("Mismatch");
        System.out.println("PQC smoke test PASSED — algorithm=" + enc.get("algorithmUsed").asText());
    }
}
const BASE_URL = "https://staging.ankatech.co";
const TENANT_ID = "00000000-0000-0000-0000-000000000003";

const tok = async (f) => (await (await fetch(`${BASE_URL}/api/v3/auth/token`, {
  method: "POST", headers: {"Content-Type": "application/x-www-form-urlencoded"},
  body: new URLSearchParams(f)})).json()).access_token;
const admin = { "Authorization": `Bearer ${await tok({grant_type:"password", username:"[email protected]", password:"•••", tenant_id:TENANT_ID})}` };
const app   = { "Authorization": `Bearer ${await tok({grant_type:"client_credentials", client_id:"…", client_secret:"…"})}` };
const jsonH = (a) => ({ ...a, "Content-Type": "application/json" });

// Discover PQC algorithms (app)
const url = new URL(`${BASE_URL}/api/v3/key-management/supported-algorithms`);
url.searchParams.set("category", "POST_QUANTUM");
url.searchParams.set("keyOps",   "encrypt,decrypt");
const algos = await (await fetch(url, { headers: app })).json();

// Pick the first candidate
const pick = algos[0];
const kid  = `smoketest-${Date.now()}`;
console.log(`Picked kty=${pick.kty} alg=${pick.alg} kid=${kid}`);

// Admin creates the key
await fetch(`${BASE_URL}/api/v3/admin/tenants/${TENANT_ID}/keys`, {
  method: "POST", headers: jsonH(admin),
  body: JSON.stringify({
    kid, kty: pick.kty, algorithm: pick.alg,
    purpose: "ENCRYPT_DECRYPT", keyOps: ["encrypt","decrypt"],
  }),
});

// Smoke test round-trip
const dataB64 = Buffer.from("PQC smoke test").toString("base64");
const enc = await (await fetch(`${BASE_URL}/api/v3/crypto/encrypt`, {
  method: "POST", headers: jsonH(app),
  body: JSON.stringify({ kid, data: dataB64 }),
})).json();
const dec = await (await fetch(`${BASE_URL}/api/v3/crypto/decrypt`, {
  method: "POST", headers: jsonH(app),
  body: JSON.stringify({ jweToken: enc.jweToken }),
})).json();

if (Buffer.from(dec.decryptedData, "base64").toString() !== "PQC smoke test")
  throw new Error("Mismatch");
console.log(`PQC smoke test PASSED — algorithm=${enc.algorithmUsed}`);
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class AlgorithmDiscovery
{
    const string BASE_URL       = "https://staging.ankatech.co";
    const string ADMIN_EMAIL    = "[email protected]";
    const string ADMIN_PASSWORD = "••••••••••••";
    const string TENANT_ID      = "00000000-0000-0000-0000-000000000003";
    const string CLIENT_ID      = "00000000-0000-0000-0000-000000000000";
    const string CLIENT_SECRET  = "••••••••••••••••••••••••••••••••";

    static async Task<string> GetToken(HttpClient http, IEnumerable<KeyValuePair<string,string>> fields)
    {
        var r = await http.PostAsync($"{BASE_URL}/api/v3/auth/token",
            new FormUrlEncodedContent(fields));
        return JsonDocument.Parse(await r.Content.ReadAsStringAsync())
                           .RootElement.GetProperty("access_token").GetString();
    }

    static async Task Main()
    {
        var http = new HttpClient();
        var adminToken = await GetToken(http, new[] {
            new KeyValuePair<string,string>("grant_type", "password"),
            new KeyValuePair<string,string>("username",   ADMIN_EMAIL),
            new KeyValuePair<string,string>("password",   ADMIN_PASSWORD),
            new KeyValuePair<string,string>("tenant_id",  TENANT_ID),
        });
        var appToken = await GetToken(http, new[] {
            new KeyValuePair<string,string>("grant_type",    "client_credentials"),
            new KeyValuePair<string,string>("client_id",     CLIENT_ID),
            new KeyValuePair<string,string>("client_secret", CLIENT_SECRET),
        });

        var adminHttp = new HttpClient();
        adminHttp.DefaultRequestHeaders.Add("Authorization", $"Bearer {adminToken}");
        var appHttp = new HttpClient();
        appHttp.DefaultRequestHeaders.Add("Authorization", $"Bearer {appToken}");

        // Discover PQC algorithms
        var algosResp = await appHttp.GetAsync(
            $"{BASE_URL}/api/v3/key-management/supported-algorithms"
            + "?category=POST_QUANTUM&keyOps=encrypt,decrypt");
        var algos = JsonDocument.Parse(await algosResp.Content.ReadAsStringAsync()).RootElement;
        var pick  = algos[0];
        var kid   = $"smoketest-{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}";
        Console.WriteLine($"Picked kty={pick.GetProperty("kty").GetString()}"
            + $" alg={pick.GetProperty("alg").GetString()} kid={kid}");

        // Admin creates the key
        await adminHttp.PostAsync(
            $"{BASE_URL}/api/v3/admin/tenants/{TENANT_ID}/keys",
            new StringContent(JsonSerializer.Serialize(new {
                kid, kty = pick.GetProperty("kty").GetString(),
                algorithm = pick.GetProperty("alg").GetString(),
                purpose = "ENCRYPT_DECRYPT", keyOps = new[] { "encrypt", "decrypt" },
            }), Encoding.UTF8, "application/json"));

        // Smoke test round-trip
        var dataB64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("PQC smoke test"));
        var encResp = await appHttp.PostAsync(
            $"{BASE_URL}/api/v3/crypto/encrypt",
            new StringContent(JsonSerializer.Serialize(new { kid, data = dataB64 }),
                              Encoding.UTF8, "application/json"));
        var enc = JsonDocument.Parse(await encResp.Content.ReadAsStringAsync()).RootElement;

        var jweToken = enc.GetProperty("jweToken").GetRawText();
        var decResp = await appHttp.PostAsync(
            $"{BASE_URL}/api/v3/crypto/decrypt",
            new StringContent($"{{ \"jweToken\": {jweToken} }}",
                              Encoding.UTF8, "application/json"));
        var dec = JsonDocument.Parse(await decResp.Content.ReadAsStringAsync()).RootElement;
        var plaintext = Encoding.UTF8.GetString(
            Convert.FromBase64String(dec.GetProperty("decryptedData").GetString()));
        if (plaintext != "PQC smoke test") throw new Exception("Mismatch");
        Console.WriteLine($"PQC smoke test PASSED — algorithm={enc.GetProperty("algorithmUsed").GetString()}");
    }
}

Query parameter cheat-sheet

GET /api/v3/key-management/supported-algorithms accepts:

ParamValuesExample
categoryCLASSICAL, POST_QUANTUM, HYBRID?category=POST_QUANTUM
statusRECOMMENDED, EXPERIMENTAL, LEGACY?status=RECOMMENDED
minSecurityLevelinteger 1-5?minSecurityLevel=3
maxSecurityLevelinteger 1-5?maxSecurityLevel=5
keyOpscomma list — algo must support ALL?keyOps=sign,verify
standardscomma list — NIST, BSI, ANSSI, ENISA, ISO?standards=NIST
ktycomma list — matches ANY?kty=ML-KEM,ML-DSA
algcomma list — matches ANY?alg=ML-KEM-768,ML-KEM-1024

Where to go next


Did this page help you?