Authentication
The LVNG API supports two authentication methods: JWT tokens (via Supabase) for user sessions, and API keys for programmatic access. Both methods resolve to a tenant-scoped request context that isolates all data operations.
Overview
Authorization: Bearer <jwt>Browser apps, user sessionsx-api-key: <key>Backend services, scripts, CI/CDJWT Tokens
LVNG uses Supabase-issued JWTs as the primary authentication method for user sessions. Tokens are validated server-side using the jsonwebtoken library against the JWT_SECRET environment variable.
Token Claims
The JWT payload contains the following claims:
{
400">class="text-emerald-400">"userId": 400">class="text-emerald-400">"uuid-of-the-user",
400">class="text-emerald-400">"email": 400">class="text-emerald-400">"user@example.com",
400">class="text-emerald-400">"role": 400">class="text-emerald-400">"admin",
400">class="text-emerald-400">"organizationId": 400">class="text-emerald-400">"org-uuid",
400">class="text-emerald-400">"iat": 1710864000,
400">class="text-emerald-400">"exp": 1710867600
}Token Lifetime
Request Example
400">curl -X 400">GET https:400">class="text-zinc-500">//api.lvng.ai/api/v2/channels \
-H 400">class="text-emerald-400">"Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H 400">class="text-emerald-400">"Content-Type: application/json"How It Works
- The user signs in via Supabase Auth (email/password, OAuth, or magic link).
- Supabase returns an access token (JWT) and a refresh token.
- Your frontend sends the access token in the
Authorizationheader with every request. - The LVNG middleware validates the JWT signature, extracts the user's identity, and stores the session in Redis with a 3600-second TTL.
- All subsequent database queries are scoped to the user's
customer_id.
Tip: Access tokens expire after 1 hour. Use the Supabase client's built-in token refresh to keep sessions alive without prompting the user to sign in again.
API Keys
API keys are designed for server-to-server communication where there is no browser session. They are long-lived credentials tied to a specific customer account and stored as bcrypt hashes in the api_keys database table with a 30-second in-memory cache for performance.
Key Format
LVNG API keys follow a fixed format that encodes the customer scope. The token portion is 32-64 random characters.
vtron_cust_{customerId}_{token}
# Example:
vtron_cust_abc123_sk_live_9f8e7d6c5b4a3210fedcba98Sending the Key
The API accepts your key via three methods. All are equivalent.
Accepted Methods
x-api-keyheaderPass the full API key as the header value. Recommended for server-to-server calls.
AuthorizationheaderPass the key as a Bearer token: "Bearer vtron_cust_...". Works when your HTTP client already sets Authorization headers.
api_keyquery paramPass the key as a query parameter: ?api_key=vtron_cust_.... Use only when headers are not available.
curl Example (x-api-key)
400">curl -X 400">POST https:400">class="text-zinc-500">//api.lvng.ai/api/v1/chat \
-H 400">class="text-emerald-400">"x-api-key: vtron_cust_abc123_sk_live_9f8e7d6c5b4a3210fedcba98" \
-H 400">class="text-emerald-400">"Content-Type: application/json" \
-d '{
400">class="text-emerald-400">"message": 400">class="text-emerald-400">"Summarize yesterday'\''s standup notes.",
400">class="text-emerald-400">"platform": 400">class="text-emerald-400">"api"
}'Plan-Based Rate Limits
API keys are associated with a plan tier that determines rate limits.
Request Context
After successful authentication, the middleware populates req.user with the following fields. All downstream handlers use this context for tenant-scoped operations.
{
400">class="text-emerald-400">"id": 400">class="text-emerald-400">"user-uuid",
400">class="text-emerald-400">"customer_id": 400">class="text-emerald-400">"customer-uuid",
400">class="text-emerald-400">"email": 400">class="text-emerald-400">"user@example.com",
400">class="text-emerald-400">"role": 400">class="text-emerald-400">"admin",
400">class="text-emerald-400">"auth_method": 400">class="text-emerald-400">"jwt", 400">class="text-zinc-500">// 400">class="text-emerald-400">"jwt" or 400">class="text-emerald-400">"api_key"
400">class="text-emerald-400">"organization_id": 400">class="text-emerald-400">"org-uuid", 400">class="text-zinc-500">// present 400">if user belongs to an org
400">class="text-emerald-400">"org_role": 400">class="text-emerald-400">"owner" 400">class="text-zinc-500">// present 400">if user belongs to an org
}Public Endpoints
The following endpoints do not require authentication. They are rate-limited by IP address (60 req/min).
/healthServer health check/capabilitiesPlatform capability discovery/v2/discoverAPI discovery endpoint/v2/ingestData ingestion webhook/v2/artifacts/metaArtifact metadata (public)/analytics/eventsAnalytics event ingestionTenant Isolation
LVNG is a multi-tenant platform. Every authentication method resolves to a customer_id. All database queries, agent executions, and workflow runs are automatically scoped to that tenant.
- •A JWT encodes the
customer_idin its claims. The middleware extracts it on every request. - •An API key embeds the
customer_iddirectly in the key prefix (vtron_cust_{customerId}_...). The middleware parses it and enforces scope. - •There is no way to query data belonging to another tenant, even with a valid token.
Security Notes
- 1.Never expose API keys in client-side code. API keys are for server environments only. Use JWT tokens for browser-based applications.
- 2.service_role keys are blocked on public endpoints. The middleware rejects Supabase service_role keys on user-facing routes to prevent privilege escalation.
- 3.API key versioning. The server tracks key versions via the
X-API-Key-Versionresponse header. Use this to verify your key is current after rotation. - 4.Rotate keys periodically. Generate new keys and revoke old ones from Settings > API Keys in the dashboard.
- 5.Use environment variables. Never hard-code keys in source files. Add
.envto your.gitignore.
Environment Variables
Store your credentials in environment variables.
# .env -- add this file to .gitignore
LVNG_API_KEY=vtron_cust_abc123_sk_live_9f8e7d6c5b4a3210fedcba98
# Optional: override the base URL for self-hosted deployments
LVNG_API_URL=https:400">class="text-zinc-500">//api.lvng.ai/api