Skip to main content

Gateway public-key registration

During bootstrap, Edge License Gateway generates an ES256 key pair locally and keeps the private key on the Host. It sends only the public JWK to Cloud through outbound HTTPS:

POST /api/v1/edge-gateways/{gatewayInstanceId}/signing-keys

The one-time enrollment token authorizes only this exact Tenant and Gateway binding. It is not a Product identifier, license credential, or reusable API credential. One Gateway may later enforce rights for multiple Products; Product authority comes from verified runtime snapshots, never from this request.

Request

Use Content-Type: application/json. Do not send Idempotency-Key: the enrollment token is consumed once and an exact replay after success returns 409.

{
"tenantId": "019c4400-0000-7000-8000-000000000001",
"enrollmentToken": "<one-time-enrollment-token>",
"publicSigningJwk": {
"kty": "EC",
"crv": "P-256",
"kid": "gateway-key-2026-01",
"use": "sig",
"alg": "ES256",
"x": "<base64url-encoded-32-byte-x-coordinate>",
"y": "<base64url-encoded-32-byte-y-coordinate>"
}
}

The body contains exactly the three shown top-level fields and is limited to 4096 UTF-8 bytes. The JWK contains exactly the seven shown public fields. Unknown, duplicate, nested, malformed or non-canonical values are rejected. Never add a private scalar or PEM material. Never log the enrollment token.

Success

201 Created returns only safe public-key receipt data:

{
"signingKeyId": "019c4400-0000-7000-8000-000000000010",
"gatewayInstanceId": "019c4400-0000-7000-8000-000000000009",
"keyId": "gateway-key-2026-01",
"publicKeyThumbprint": "<rfc-7638-sha256-base64url>",
"registeredAtUtc": "2026-08-07T16:30:00Z",
"supersededKeyId": null
}

All responses include Cache-Control: no-store and Pragma: no-cache. Registration does not activate the Gateway; Cloud trust-document issuance is a separate step.

Errors and retry

Errors use the standard code, message, correlationId envelope and never echo Tenant, Gateway, token or key material.

HTTPCodeMeaning
400validation.failedBody or public JWK is invalid, including forbidden private material
401relay.enrollment_invalidToken does not match the exact Tenant/Gateway enrollment
403relay.forbiddenEnrollment expired or Gateway state forbids registration
409relay.conflictToken was consumed, key conflicts, or a concurrent registration won
413validation.failedBody exceeds 4096 bytes
415validation.failedContent type is not JSON
503relay.unavailableStored registration state is temporarily unavailable

Validation failures happen before token consumption, so the corrected request may use the same token. After a timeout or 409, do not retry blindly: the first request may have committed. Obtain a new enrollment through the operator workflow. Repeated 503 with a correlation ID requires support investigation.

Security boundary

  • Generate and protect the private key locally; Cloud accepts public material only.
  • Use production TLS and outbound Host-to-Cloud connectivity. Cloud never opens an inbound connection to the Host and the Host never connects to Cloud RabbitMQ or a Cloud database.
  • Do not use request configuration, Product codes or entitlements as identity.
  • The complete Relay engine and Host internals remain proprietary; this page documents only the supported bootstrap wire contract.

See also Local Relay and Security overview.