Skip to content

API Authentication

PiVirt APIs support multiple secure authentication methods depending on the protocol, deployment model, and calling service.

Terminal window
# Using client certificates
grpcurl \
-cert ~/.config/pvcli/client.crt \
-key ~/.config/pvcli/client.key \
-cacert ~/.config/pvcli/ca.crt \
agent.pilab.hu:8443 \
pivirt.vm.v1.VMService/ListVMs
Terminal window
# Using PiTrust issued client certificates
grpcurl \
-cert /etc/pivirt/certs/agent-client.crt \
-key /etc/pivirt/certs/agent-client.key \
-cacert /etc/pivirt/certs/ca-chain.pem \
agent.pilab.hu:8443 \
pivirt.vm.v1.VMService/ListVMs
Terminal window
# Using JWT token
grpcurl \
-H "authorization: Bearer $TOKEN" \
-insecure \
agent.pilab.hu:8443 \
pivirt.vm.v1.VMService/ListVMs
Terminal window
# Using JWT token
curl -H "Authorization: Bearer $TOKEN" \
https://agent.pilab.hu:8443/api/v1/vms
Terminal window
# Using API key
curl -H "X-API-Key: $API_KEY" \
https://agent.pilab.hu:8443/api/v1/vms
Terminal window
# Using username/password (not recommended for production)
curl -u "admin:password" \
https://agent.pilab.hu:8443/api/v1/vms

The director’s console, screenshot and realtime routes are WebSocket (or binary) endpoints outside /api/v1, and they require the same access token as every other call:

Route Purpose
GET /api/terminals/{vmId} Serial console (xterm)
GET /api/terminals/{vmId}/vnc VNC (noVNC)
GET /api/screenshot/{vmId} Framebuffer screenshot
GET /api/realtime Cluster event stream

A browser cannot set an Authorization header on a WebSocket upgrade, so these routes accept the token either as a bearer header or as a token query parameter:

Terminal window
# Header (non-browser clients)
websocat -H "Authorization: Bearer $TOKEN" wss://director.pilab.hu/api/terminals/$VM_ID/vnc
# Query parameter (browsers)
wss://director.pilab.hu/api/terminals/$VM_ID/vnc?token=$TOKEN

A present-but-malformed Authorization header is rejected outright; it does not fall back to the query parameter. Missing or invalid tokens return 401 with code: missing_token or code: invalid_token.

Scope of this check. The token proves who is connecting (PIVIRT-181), and the handler then reads the VM through the caller’s tenant namespaces (PIVIRT-182): a VM the caller has no binding for returns 404. The permanent mechanism is a short-lived, single-VM console ticket minted by the GraphQL API (PIVIRT-187), which will retire the query-parameter form.

The director’s organisation API (pilab.cli.v1.AdminService, what pvcli org uses) authenticates with the same bearer token and resolves the caller’s RoleBindings before any resolver runs. A missing or invalid token is Unauthenticated; a valid token with no bindings sees nothing — every namespaced call reads as NotFound. See Multi-Tenancy.

Terminal window
# OIDC login
pvcli auth login --oidc
# Get token
pvcli auth token get
Terminal window
# Refresh token
pvcli auth refresh
Terminal window
# Inspect token
pvcli auth token inspect
Terminal window
pvcli auth serviceaccount create \
--name "ci-pipeline" \
--namespace "production" \
--role "operator"
Terminal window
pvcli auth apikey create \
--service-account "ci-pipeline" \
--namespace "production" \
--ttl 30d
Terminal window
export PIVIRT_API_KEY="pivirt_apikey_..."
pvcli vm list
sequenceDiagram
    participant User
    participant pvcli
    participant OIDC as OIDC Provider
    participant agent

    User->>pvcli: auth login --oidc
    pvcli->>OIDC: Authorization request
    OIDC-->>User: Login page
    User->>OIDC: Credentials
    OIDC-->>pvcli: Authorization code
    pvcli->>OIDC: Exchange code for token
    OIDC-->>pvcli: JWT token
    pvcli->>agent: Request with JWT
    agent->>agent: Validate JWT
    agent-->>pvcli: Response
sequenceDiagram
    participant Client
    participant agent

    Client->>agent: TLS handshake
    agent->>Client: Request client certificate
    agent->>agent: Verify certificate with PiTrust CA
    agent->>agent: Extract Certificate SAN / Subject
    agent->>agent: Check RBAC
    agent-->>Client: TLS established
    Client->>agent: gRPC request
    agent-->>Client: gRPC response
Terminal window
# Check token validity
pvcli auth status
# Verify certificate
openssl x509 -in ~/.config/pvcli/client.crt -text -noout
# Test connection
grpcurl -insecure agent.pilab.hu:8443 list
Issue Resolution
Token expired Refresh token: pvcli auth refresh
Certificate expired Regenerate certificate
Invalid credentials Check username/password
Permission denied Check RBAC policy