Authentication

The LVNG API supports two authentication methods: JWT tokens (via Supabase) for user sessions, per-user API keys (lvng_sk_*) for programmatic access and Claude Code, and service API keys for backend services. All methods resolve to a tenant-scoped request context that isolates all data operations.

Overview

MethodHeaderBest For
JWT TokenAuthorization: Bearer <jwt>Browser apps, user sessions
Per-User API KeyAuthorization: Bearer YOUR_API_KEYClaude Code, SDKs, scripts, CI/CD

JWT 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:

JWT Payload
{
  "userId": "uuid-of-the-user",
  "email": "user@example.com",
  "role": "admin",
  "organizationId": "org-uuid",
  "iat": 1710864000,
  "exp": 1710867600
}

Token Lifetime

Token TypeTTL
Access token1 hour
Refresh token7 days
Redis session cache3600 seconds

Request Example

Terminal -- JWT Auth
curl -X GET https://api.lvng.ai/api/v2/channels \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json"

How It Works

  1. The user signs in via Supabase Auth (email/password, OAuth, or magic link).
  2. Supabase returns an access token (JWT) and a refresh token.
  3. Your frontend sends the access token in the Authorization header with every request.
  4. The LVNG middleware validates the JWT signature, extracts the user's identity, and stores the session in Redis with a 3600-second TTL.
  5. 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.

Per-User API Keys

Per-user API keys are the recommended way to authenticate programmatic access. They are scoped to your user account and workspace, support fine-grained permission scopes, and are stored as SHA-256 hashes. Generate keys from Settings > Developer or via the API Keys API.

Key Format

Key Format
lvng_sk_live_7e8949d627f560d298f310ceeadb492c
│       │    └── 32 random hex characters
│       └── Environment (live / test)
└── Prefix (per-user key identifier)

Sending the Key

The API accepts your key via three methods. All are equivalent.

Accepted Methods

Authorizationheader

Pass the key as a Bearer token: "Bearer lvng_sk_live_...". Recommended for all API calls.

x-api-keyheader

Pass the full API key as the header value. Supported as an alternative to the Authorization header.

api_keyquery param

Pass the key as a query parameter: ?api_key=lvng_sk_live_.... Use only when headers are not available.

curl Example

Terminal -- Authorization: Bearer
curl https://api.lvng.ai/api/v2/workflows \
  -H "Authorization: Bearer lvng_sk_live_7e8949d627f560d298f310ceeadb492c"

Claude Code Setup

Connect Claude Code to your workspace by adding the LVNG MCP server to your Claude settings:

Claude Code Configuration
// ~/.claude/settings.json
{
  "mcpServers": {
    "lvng": {
      "command": "npx",
      "args": ["@lvng/mcp-server"],
      "env": {
        "LVNG_API_KEY": "lvng_sk_live_..."
      }
    }
  }
}

Plan-Based Rate Limits

PlanPer MinutePer HourPer Day
Free605005,000
Pro3005,00050,000
Enterprise1,000UnlimitedUnlimited

Request Context

After successful authentication, the middleware populates req.user with the following fields. All downstream handlers use this context for tenant-scoped operations.

req.user object
{
  "id": "user-uuid",
  "customer_id": "customer-uuid",
  "email": "user@example.com",
  "role": "admin",
  "auth_method": "jwt",           // "jwt" or "per_user_api_key"
  "scopes": ["read", "write"],    // present for API key auth
  "workspace_id": "ws-uuid",      // present for API key auth
  "organization_id": "org-uuid",  // present if user belongs to an org
  "org_role": "owner"             // present 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 ingestion

Tenant 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_id in its claims. The middleware extracts it on every request.
  • A per-user API key (lvng_sk_*) is validated against a SHA-256 hash in the database, which returns the associated user_id and customer_id.
  • 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-Version response header. Use this to verify your key is current after rotation.
  • 4.Rotate keys periodically. Generate new keys and revoke old ones from Settings > Developer or via the API Keys API.
  • 5.Use environment variables. Never hard-code keys in source files. Add .env to your .gitignore.

Environment Variables

Store your credentials in environment variables.

.env
# .env -- add this file to .gitignore
LVNG_API_KEY=lvng_sk_live_7e8949d627f560d298f310ceeadb492c

# Optional: override the base URL for self-hosted deployments
LVNG_API_URL=https://api.lvng.ai

Next Steps