Skip to content

Control-Plane Authentication

This document describes the authentication and authorization options currently implemented in control-plane/service as of March 10, 2026.

The control-plane supports these runtime auth modes:

  1. auth-disabled (no authentication; development/testing mode).
  2. OIDC browser session auth (currently Google OIDC via login/callback).
  3. OIDC bearer auth for tools/CLI (ID token in Authorization: Bearer ...).
  4. Hybrid mode: browser session auth + bearer auth enabled together.

Set:

  • -auth-enabled=false

Behavior:

  • Requests are treated as an admin principal internally.
  • No cookie session or bearer token is required.
  • Intended for local/dev scenarios only.

Important caveat:

  • POST /v1/agent-registration-tokens requires an authenticated subject (sub) to mint registration tokens. In auth-disabled mode, no subject exists, so this endpoint returns unauthorized.

Set:

  • -auth-enabled=true
  • -auth-google-enabled=true
  • -auth-state-secret=...
  • -auth-google-client-id=...
  • -auth-google-client-secret=...
  • -auth-google-redirect-url=...
  • optional -auth-google-issuer-url=... (defaults to https://accounts.google.com)
  • optional -auth-google-scopes=openid,profile,email

Flow:

  1. GET /v1/auth/providers
  2. GET /v1/auth/login?provider=google
  3. GET /v1/auth/callback/google
  4. Server creates cookie session + CSRF cookie.

Session details:

  • Default cookie names:
    • session: guardian_session
    • csrf: guardian_csrf
  • Default session max age: 12h
  • Default idle timeout: 2h
  • Mutating endpoints require CSRF (header X-CSRF-Token must match CSRF cookie).

Set:

  • -auth-enabled=true
  • -auth-bearer-enabled=true
  • -auth-bearer-issuer-url=...
  • -auth-bearer-client-id=...
  • optional -auth-bearer-scopes=openid,profile,email

Flow:

  1. Tool calls GET /v1/auth/device-config.
  2. Tool discovers OIDC metadata from issuer (/.well-known/openid-configuration).
  3. Tool obtains OIDC ID token (device flow or equivalent).
  4. Tool calls control-plane with Authorization: Bearer <id_token>.

Verification model:

  • Bearer token is verified against issuer JWKS and expected audience (client_id).
  • This path expects an OIDC ID token.
  • Bearer principal is mapped to role member (not admin).
  • CSRF is not required for bearer-authenticated requests.

Enable both:

  • auth.google.enabled=true
  • auth.bearer.enabled=true

Use cases:

  • Console users authenticate via browser session.
  • CLI tools (for example OpenFleet) authenticate via bearer ID token.
  • admin: full control-plane access, including user management and agent revoke/restore.
  • member: scoped agent visibility and onboarding operations.
  • GET /health: public.
  • GET /v1/auth/providers: public (auth config discovery).
  • GET /v1/auth/device-config: public when bearer auth enabled.
  • GET /v1/auth/login: public (starts browser auth flow).
  • GET /v1/auth/callback/{provider}: public (OIDC callback).
  • POST /v1/auth/logout: authenticated principal.
    • cookie session calls require CSRF.
  • GET /v1/me: authenticated principal.
  • GET /v1/users: admin only.
  • PATCH /v1/users/{id}: admin only.
    • cookie session calls require CSRF.
  • POST /v1/agent-registration-tokens: authenticated principal.
    • cookie session calls require CSRF.
    • bearer calls do not require CSRF.
  • GET /v1/agents: authenticated principal.
    • admin: all agents.
    • member: filtered to agents bound to the caller subject.
  • GET /v1/agents/{id}: authenticated principal.
    • admin: full access.
    • member: only if caller has active binding.
  • GET /v1/projects/{project_uuid}/agents: project-scoped agent list.
    • Governance Studio project: requires a bearer token authorized by Auth Service for view_project_data on the bound Governance project.
    • operator project: admin only.
    • Auth Service authorization failures and outages fail closed; an outage returns 503 Service Unavailable.
  • GET /v1/projects/{project_uuid}/agents/{agent_id}: project-scoped agent detail by Gateway agent ID or membership subject DID.
    • uses the same Governance Studio view_project_data or operator-admin authorization as the project list.
    • returns only identities derived from membership evidence for the requested project; local key detail is restricted to the matching membership subject DID.
  • POST /v1/agents/{id}/revoke: admin only (CSRF required for cookie session).
  • POST /v1/agents/{id}/restore: admin only (CSRF required for cookie session).
  • GET /v1/agents/{id}/status-events: admin only.

Endpoint: POST /v1/agent-registration-tokens

Request:

  • agent_name (required)
  • agent_handle (optional, deterministic handle)
  • agent_id is rejected (managed by control-plane)

Behavior:

  • Subject (sub) is taken from authenticated principal external subject.
  • If agent_handle is provided, deterministic agent_id is generated.
  • Otherwise, agent_id includes a random suffix.
  • Token TTL is currently 15 minutes.
  • Response command is a template using VIPER_PROVISIONING_TOKEN placeholder (raw token is returned only in registration_token).
  • -auth-enabled / CONTROL_PLANE_AUTH_ENABLED
  • -auth-registration-token-secret / CONTROL_PLANE_AUTH_REGISTRATION_TOKEN_SECRET
  • -auth-registration-token-issuer / CONTROL_PLANE_AUTH_REGISTRATION_TOKEN_ISSUER
  • -auth-allowed-email-domains / CONTROL_PLANE_AUTH_ALLOWED_EMAIL_DOMAINS
  • -auth-bootstrap-admin-email / CONTROL_PLANE_AUTH_BOOTSTRAP_ADMIN_EMAIL
  • -auth-cookie-domain / CONTROL_PLANE_AUTH_COOKIE_DOMAIN
  • -auth-cookie-secure / CONTROL_PLANE_AUTH_COOKIE_SECURE
  • -auth-session-max-age / CONTROL_PLANE_AUTH_SESSION_MAX_AGE
  • -auth-session-idle-timeout / CONTROL_PLANE_AUTH_SESSION_IDLE_TIMEOUT
  • -auth-ui-base-url / CONTROL_PLANE_AUTH_UI_BASE_URL
  • -auth-google-enabled / CONTROL_PLANE_AUTH_GOOGLE_ENABLED
  • -auth-state-secret / CONTROL_PLANE_AUTH_STATE_SECRET
  • -auth-google-issuer-url / CONTROL_PLANE_AUTH_GOOGLE_ISSUER_URL
  • -auth-google-client-id / CONTROL_PLANE_AUTH_GOOGLE_CLIENT_ID
  • -auth-google-client-secret / CONTROL_PLANE_AUTH_GOOGLE_CLIENT_SECRET
  • -auth-google-redirect-url / CONTROL_PLANE_AUTH_GOOGLE_REDIRECT_URL
  • -auth-google-scopes / CONTROL_PLANE_AUTH_GOOGLE_SCOPES
  • -auth-bearer-enabled / CONTROL_PLANE_AUTH_BEARER_ENABLED
  • -auth-bearer-issuer-url / CONTROL_PLANE_AUTH_BEARER_ISSUER_URL
  • -auth-bearer-client-id / CONTROL_PLANE_AUTH_BEARER_CLIENT_ID
  • -auth-bearer-scopes / CONTROL_PLANE_AUTH_BEARER_SCOPES

Helm Values (deploy/charts/guardian-stack)

Section titled “Helm Values (deploy/charts/guardian-stack)”

Auth values:

  • controlPlane.auth.enabled
  • controlPlane.auth.registrationTokenSecret
  • controlPlane.auth.registrationTokenIssuer
  • controlPlane.auth.google.*
  • controlPlane.auth.bearer.enabled
  • controlPlane.auth.bearer.issuerURL
  • controlPlane.auth.bearer.clientID
  • controlPlane.auth.bearer.scopes

Secret keys used by control-plane auth secret:

  • stateSecret (required when auth.google.enabled=true)
  • registrationTokenSecret
  • googleClientID (when Google enabled)
  • googleClientSecret (when Google enabled)

OpenFleet now uses bearer OIDC device flow for onboarding:

  • openfleet auth login -> reads /v1/auth/device-config, performs OIDC device flow, stores local session.
  • openfleet agents create --guardian-onboard -> mints registration token via control-plane and passes provisioning data to runtime.
  • Runtime (OpenClaw + viper) generates DID key material and registers with llm-gateway using the provisioning token.
  • openfleet agents onboard <name> -> rotates provisioning token for an existing runtime-provisioned workload.

This aligns tool onboarding with the same identity/trust model used by control-plane and gateway.