Skip to content

JWKS API ​

The server publishes its Ed25519 public key(s) as a JWKS document so the hub can verify JWTs the server signed.

The machine-readable OpenAPI spec for this endpoint lives alongside this page at docs/reference/api/hub-jwks.yaml.

Endpoint ​

GET /.well-known/jwks.json

Served directly by the Phlix server — it is not proxied through the hub. No authentication is required; the document contains public key material only.

Response — 200 OK ​

json
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "<base64url-encoded 32-byte public key>",
      "kid": "<key id>",
      "use": "sig",
      "alg": "EdDSA"
    }
  ]
}

Headers:

HeaderValue
Content-Typeapplication/json
Cache-Controlpublic, max-age=3600 (cacheable for one hour)

JWK fields ​

FieldValueMeaning
ktyOKPOctet Key Pair — the Ed25519/Ed448 key type
crvEd25519Edwards curve identifier
xbase64urlThe 32-byte Ed25519 public key
kidstringKey ID — base64url(SHA-256(publicKey)[0..8]), or an ISO 8601 timestamp for newly generated keys
usesigSignature use
algEdDSAEdDSA signatures

Response — 429 Too Many Requests ​

This endpoint is publicly reachable, so it carries a DoS guard keyed on the trusted client IP (trusted-proxy aware, so a forged X-Forwarded-For cannot mint a fresh bucket). Exceeding the budget returns 429 with a Retry-After header.

The budget is configurable from Settings → Server via server.rate_limit.jwks.max and server.rate_limit.jwks.window (default: 120 requests per 60 seconds). Note that these are restart-scoped — the limiters capture their values when the container is built, so a change takes effect on the next restart. See Server Settings.

Graceful degradation ​

If the private key cannot be loaded, the endpoint returns a valid but empty keyset with HTTP 200 rather than failing:

json
{ "keys": [] }

The failure is logged server-side. This is deliberate: a problem with the signing key must never take the public JWKS endpoint down, because that would break hub verification for every other reason too.

The private key ​

The corresponding private key is read from config/hub-server-key.pem and is never exposed over the network. The reader accepts both formats:

  • the app's native -----BEGIN ED25519 PRIVATE KEY-----
  • a standard PKCS#8 Ed25519 key (-----BEGIN PRIVATE KEY-----), such as one produced by openssl genpkey -algorithm Ed25519

See Config Files for where this file lives, and Pairing Protocol for how the signed JWTs are used.

BSD-3-Clause