Skip to content

Sidecar Agent Registration Integration Guide

Status: Active integration contract Last updated: 2026-03-04 Applies to: llm-gateway/service (github.com/eqtylab/gateway/llm-gateway/service)

This guide defines how an agent-side sidecar should register an agent with the gateway trusted registry.

The sidecar is responsible for:

  • creating/holding agent signing key material
  • requesting a provisioning token from enterprise bootstrap flow
  • calling gateway registration endpoint
  • retrying safely using idempotent semantics

The gateway is responsible for:

  • validating provisioning token
  • persisting agent/key/user state
  • enabling subsequent RFC 9421 verification by did:key (keyid)

Method and path:

POST /v1/agents/registrations

Availability:

  • gateway flag -agent-registration-enabled=true
  • gateway flag -registry-backend=postgres

Required header:

  • Content-Type: application/json

Optional header:

  • X-Guardian-Correlation-Id (if omitted, gateway generates one)
{
"agent_id": "agent:demo",
"did": "did:key:z6Mkt2HssyBGaThf7ofBwQvVcPLXnBWvgZp7s3K4DkCyLLjz",
"did_source": "Software (ed25519)",
"display_name": "Demo Agent",
"provisioning_token": "ggr1.<payload_b64url>.<sig_b64url>"
}

Field rules:

  • agent_id required and canonical
  • did required and must be a did:key multikey identifier (Ed25519 or P-256)
  • did_source required — records the integrity signer type that produced the DID. Accepted values: "Software (ed25519)", "Software (p256)", "YubiKey"
  • provisioning_token required
  • display_name optional

The initial user-to-agent binding is derived gateway-side from the provisioning token’s subject claim; the request body itself carries no users field.

Success (201 for created, 200 for updated/noop):

{
"agent_id": "agent:demo",
"agent_status": "active",
"key_status": "active",
"registration_result": "created",
"registered_at": 1771874800,
"vc": {
"@context": ["https://www.w3.org/ns/credentials/v2", "..."],
"type": ["VerifiableCredential", "GuardianAgentCredential"],
"issuer": "did:key:...",
"credentialSubject": { "id": "did:key:z6Mkt..." },
"proof": { "type": "Ed25519Signature2020", "...": "..." }
},
"correlation_id": "..."
}

vc is the W3C Verifiable Credential the gateway issues for the registered DID (Ed25519Signature2020). The field is always present; the sidecar should persist it and later include its CID in the signed X-Viper-Credential-CID list. The older X-Viper-Verifiable-Credential-CID header is deprecated and accepted only for migration compatibility.

registration_result values:

  • created: new agent record created
  • updated: existing agent updated, or key rotated, or users changed
  • noop: same active (agent_id, did) and no state changes

Error payload:

{
"code": "registration_invalid_token",
"message": "provisioning token validation failed",
"correlation_id": "..."
}

Error codes:

  • registration_invalid_request (400)
  • registration_invalid_token (401)
  • registration_conflict (409)
  • registration_internal_error (500)

Current format:

ggr1.<payload_b64url>.<sig_b64url>

Payload claims:

  • jti
  • agent_id
  • sub
  • iat
  • exp

Signature:

  • HMAC-SHA256(secret, "ggr1.<payload_b64url>")

Registration token secret is configured in gateway via standardized runtime config (registry-registration-token-secret, LLM_GATEWAY_REGISTRATION_TOKEN_SECRET, or TOML registry.registration_token_secret).

Sidecar should treat registration as safe-to-retry:

  • network timeout: retry with same payload/token if token still valid
  • 5xx: retry with exponential backoff and jitter
  • 429 (future): retry with backoff
  • 4xx: do not blind-retry; inspect code and fix payload/token

Gateway idempotency behavior:

  • same (agent_id, did) => noop
  • new did for an existing agent_id => new active key record (updated)
  • revoked agents are not reactivated by registration (registration_conflict); restore must be performed via control-plane kill-switch API

When sidecar rotates signing key for an agent:

  1. Generate new key pair.
  2. Re-register using same agent_id and the new did:key.
  3. Gateway stores the new key record for that agent as active.
  4. Sidecar begins signing traffic with new private key immediately after successful registration.
  1. Sidecar obtains bootstrap token.
  2. Sidecar calls registration endpoint.
  3. Sidecar stores registration_result + correlation_id in local logs.
  4. Sidecar signs traffic with keyid=did:key:z... (Ed25519 or P-256 multikey DID).
  5. Gateway verifies signature directly from did:key and enforces replay/attestation rules.

After registration, sidecar request signatures must use:

keyid="did:key:z..."

10. Local End-to-End Test (without sidecar code)

Section titled “10. Local End-to-End Test (without sidecar code)”

From repo root:

Terminal window
just --justfile llm-gateway/justfile audit-db-up
just --justfile llm-gateway/justfile gateway-registry

In another shell:

Terminal window
SEED=$(just --justfile llm-gateway/justfile gen-key | awk -F= '/seed_b64url/{print $2; exit}')
TOKEN=$(just --justfile llm-gateway/justfile reg-token | awk -F= '/^token=/{print $2; exit}')
just --justfile llm-gateway/justfile e2e-prepare-registry "$TOKEN" "$SEED"
just --justfile llm-gateway/justfile e2e-success

This exercises:

  • registration write path
  • DID-based signature verification
  • RFC 9421 verification and forwarding
  • sidecar must never log private key seed
  • sidecar should avoid logging full provisioning token
  • gateway stores registration event payload with provisioning token redacted
  • use short token TTLs and rotate registration token secrets operationally
  • llm-gateway/docs/agent-registry.md
  • llm-gateway/docs/verification.md
  • llm-gateway/docs/local-development.md