Authentication & HTTPS
vibeD protects its MCP and API endpoints with bearer token authentication, using the official MCP SDK auth middleware. This ensures MCP clients like Claude Desktop, Cursor, and others can securely connect to your vibeD instance.
Why Authenticate?
MCP clients do not trust unsecured tool servers. Without authentication:
- Any process on the network could invoke deployment tools
- Built artifacts and source code could be exposed
- There is no audit trail of who deployed what
With auth disabled, every request is treated as admin. To stop that being exposed by accident, vibeD refuses to start when auth is disabled and the server binds a non-loopback address, unless you explicitly acknowledge it with auth.devInsecure: true. Use that only for local dev or a network-isolated in-cluster listener; the Helm chart's no-auth path sets it for you. The right move for anything reachable by others is to enable auth.
Quick Start
The fastest way to enable auth is via a single environment variable:
export VIBED_AUTH_API_KEY="vibed_sk_your_secret_key_here"
./vibed --config vibed.yaml --transport http
This automatically enables API key authentication. MCP clients then connect with:
Authorization: Bearer vibed_sk_your_secret_key_here
Authentication Modes
API Key Mode (Default)
Simple bearer tokens validated against a configured list. Best for single-user setups, CI/CD pipelines, and development.
auth:
enabled: true
mode: "apikey"
apiKeys:
- key: "env:VIBED_API_KEY" # Resolved from environment variable
name: "default"
- key: "vibed_sk_ci_deploy_key" # Literal value
name: "ci-pipeline"
scopes: ["deploy"]
Key features:
- Keys can be literal values or resolved from environment variables using the
env:prefix - Keys also support
file:/path/to/tokento read tokens from files - Each key has a human-readable
name; the owning user identity (UserID) isapikey-<name>, and a user record is auto-provisioned under that ID on first authentication - Optional
scopesrestrict what the key can do (empty = unrestricted) - Constant-time comparison prevents timing attacks
- Suspension is enforced: setting a key's user record
status: suspendedimmediately revokes access on the next request (401)
The canonical user ID for a static API key is now apikey-<name> everywhere — request identity, the provisioned user record, the role map, and artifact ownership. Before v0.4.4 the raw name was used for ownership, so artifacts deployed by a static-key user on an older version are owned under the bare name and won't match after upgrade. If you rely on static-key owner-scoping with pre-existing artifacts, re-key their ownership or redeploy. OIDC and no-auth users are unaffected.
OIDC Mode
For production environments with an OpenID Connect identity provider (Keycloak, Auth0, Okta, Google). vibeD validates JWT tokens directly against the provider's JWKS endpoint.
auth:
enabled: true
mode: "oidc"
oidc:
issuer: "https://auth.example.com/realms/vibed" # OIDC issuer URL
audience: "vibed" # Expected audience claim
usernameClaim: "preferred_username" # JWT claim for username
emailClaim: "email" # JWT claim for email
roleClaim: "realm_access.roles" # JWT claim for roles
adminRole: "vibed-admin" # Role value that grants admin access
scopes: # Scopes to request
- "openid"
- "profile"
- "email"
vibeD publishes an OAuth Protected Resource Metadata endpoint at /.well-known/oauth-protected-resource so MCP clients can discover the authorization server automatically.
Environment variable overrides:
| Variable | Description |
|---|---|
VIBED_AUTH_OIDC_ISSUER | OIDC issuer URL |
VIBED_AUTH_OIDC_AUDIENCE | Expected audience claim |
VIBED_AUTH_OIDC_ADMIN_ROLE | Role that grants admin access |
OAuth Proxy Mode
For environments where an external OAuth gateway or reverse proxy validates tokens. vibeD trusts the proxy to authenticate requests.
auth:
enabled: true
mode: "oauth"
The external proxy (e.g., OAuth2 Proxy, Pomerium, or an API gateway) should:
- Validate the OAuth token against your identity provider
- Forward the request to vibeD with the original
Authorization: Bearerheader - Set the
X-Forwarded-Userheader with the authenticated user's identity
Custom Modes (Extensible Registry)
Auth modes are a registry, not a fixed enum. The core registers apikey, oauth, and oidc from init(), and an out-of-tree Go module can register additional modes (for example a SAML SP or a bespoke JWT issuer) the same way — without patching the core. Set auth.mode to the registered name and vibeD resolves the provider at startup:
auth:
enabled: true
mode: "saml" # any registered mode; unknown modes fail fast at startup
An unknown auth.mode is rejected at startup with an error listing the registered modes, so a typo can never silently disable auth.
Each mode is a provider that contributes a required token Verifier — checked on every authenticated request — and, optionally, a set of public login routes. The built-in bearer-only modes (apikey, oauth, oidc) contribute no routes. A mode whose login flow needs browser-facing endpoints (for example an SSO metadata document or an assertion-consumer / callback endpoint) declares them as routes, and vibeD mounts those routes outside the bearer-auth middleware. That is deliberate: a login route is how a caller obtains a session in the first place, so it cannot itself require one. Login routes must live on public paths — not under /api, /v1, /mcp, or /internal/sources/.
See Custom Auth Providers for the extension surface, the exported types in pkg/plugin, and how to build a custom binary.
What Gets Protected
| Endpoint | Authentication |
|---|---|
/mcp/* | Required when auth is enabled |
/api/* | Required when auth is enabled |
/api/share/* | Always open (public share links) |
/healthz | Always open (Kubernetes liveness probe) |
/readyz | Always open (Kubernetes readiness probe) |
/metrics | Always open (Prometheus scraping) |
/ (dashboard) | Always open (static frontend assets) |
HTTPS / TLS
Since bearer tokens are sent on every request, running without TLS exposes credentials on the network. vibeD supports three TLS configurations:
Certificate Files (Production)
Use certificates from cert-manager, Let's Encrypt, or your PKI:
auth:
tls:
enabled: true
certFile: "/etc/vibed/tls/tls.crt"
keyFile: "/etc/vibed/tls/tls.key"
Or via environment variables:
export VIBED_TLS_ENABLED=true
export VIBED_TLS_CERT_FILE=/etc/vibed/tls/tls.crt
export VIBED_TLS_KEY_FILE=/etc/vibed/tls/tls.key
Auto-Generated Self-Signed Certificate (Development)
For local development and testing, vibeD can generate a self-signed certificate automatically:
auth:
tls:
enabled: true
autoTLS: true
Or:
export VIBED_TLS_ENABLED=true
export VIBED_TLS_AUTO=true
The self-signed certificate covers localhost, 127.0.0.1, ::1, and the system hostname. MCP clients will need to trust this certificate or skip verification.
Do not use autoTLS in production. Use proper certificates from a trusted CA.
TLS Termination at Ingress (Kubernetes)
In Kubernetes, TLS is typically terminated at the Ingress controller. In this case, disable TLS in vibeD and configure your Ingress:
# vibed.yaml — no TLS needed, Ingress handles it
auth:
enabled: true
mode: "apikey"
# tls not enabled — Ingress terminates TLS
# Kubernetes Ingress with cert-manager
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vibed
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- vibed.example.com
secretName: vibed-tls
rules:
- host: vibed.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: vibed
port:
number: 8080
Helm Chart Setup
Enable Auth with a Secret
Create a Kubernetes Secret with your API key:
kubectl create secret generic vibed-auth \
--from-literal=api-key="vibed_sk_your_secret_key_here"
Then enable auth in your Helm values:
auth:
enabled: true
mode: "apikey"
existingSecret: "vibed-auth" # References the Secret above
Enable TLS with cert-manager
Create a Certificate resource:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: vibed-tls
spec:
secretName: vibed-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- vibed.example.com
Then enable TLS in your Helm values:
auth:
enabled: true
mode: "apikey"
tls:
enabled: true
existingSecret: "vibed-tls" # References the cert-manager Secret
Artifact Ownership
When authentication is enabled, vibeD enforces per-user artifact isolation:
- Deploy stamps each artifact with the deploying user's
owner_id(the API key'snamefield) - List only returns artifacts owned by the current user
- Status, Update, Delete, and Logs verify ownership before proceeding
- Accessing another user's artifact returns "not found" (not "forbidden") to avoid leaking artifact existence
When authentication is disabled, ownership checks are skipped and all users see all artifacts.
Connecting MCP Clients
Claude Desktop
Add vibeD as a remote MCP server in Claude Desktop settings:
{
"mcpServers": {
"vibed": {
"url": "https://vibed.example.com/mcp/",
"headers": {
"Authorization": "Bearer vibed_sk_your_secret_key_here"
}
}
}
}
Environment Variables Reference
| Variable | Description | Example |
|---|---|---|
VIBED_AUTH_API_KEY | Set a single API key (auto-enables auth) | vibed_sk_... |
VIBED_AUTH_ENABLED | Enable/disable authentication | true |
VIBED_AUTH_MODE | Authentication mode | apikey, oidc, or oauth |
VIBED_AUTH_OIDC_ISSUER | OIDC issuer URL | https://auth.example.com |
VIBED_AUTH_OIDC_AUDIENCE | OIDC expected audience | vibed |
VIBED_AUTH_OIDC_ADMIN_ROLE | OIDC role granting admin | vibed-admin |
VIBED_TLS_ENABLED | Enable HTTPS | true |
VIBED_TLS_CERT_FILE | Path to TLS certificate | /etc/tls/tls.crt |
VIBED_TLS_KEY_FILE | Path to TLS private key | /etc/tls/tls.key |
VIBED_TLS_AUTO | Generate self-signed cert | true |