Skip to main content

Overview

Dakora supports multiple authentication methods to protect your API endpoints and manage access control:
  1. API Key Authentication — for programmatic access and integrations (recommended for server‑to‑server)
  2. JWT Authentication (Clerk) — for browser and user‑initiated flows
  3. Development Mode — no authentication (local development only)
Priority order per request:
  1. API Key via X-API-Key
  2. JWT Bearer via Authorization: Bearer <token>
  3. No‑auth (only when AUTH_REQUIRED=false)

Authentication Modes

Production Mode (Auth Enabled)

When AUTH_REQUIRED=true:
  • All API endpoints require valid auth
  • Multi‑tenant scoping applies (user/workspace/project)
  • Unauthorized requests return 401/403

Development Mode (No Auth)

When AUTH_REQUIRED=false:
  • Endpoints are public (no headers required)
  • Intended for local development only
  • Requests are scoped to a default project

Frontend Setup (Clerk JWT)

Create studio/.env.local:
# Enable authentication
VITE_AUTH_REQUIRED=true

# Clerk
VITE_CLERK_PUBLISHABLE_KEY=pk_test_YOUR_KEY_HERE

# API
VITE_API_URL=http://localhost:8000
Run the frontend:
cd studio
npm install
npm run dev

Backend Setup

Set environment variables in your backend .env or deployment:
# Enable authentication
AUTH_REQUIRED=true

# Clerk JWT verification
CLERK_JWT_ISSUER=https://YOUR-CLERK-DOMAIN.clerk.accounts.prod.liveblocks.io
CLERK_JWKS_URL=https://YOUR-CLERK-DOMAIN.clerk.accounts.prod.liveblocks.io/.well-known/jwks.json

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/dakora

API Key Authentication (Project‑Scoped)

Generate API Keys

  • Web App
  • API (JWT required)
Use Settings → API Keys to create a project API key. Keys are shown once; copy and store securely.

Use API Keys

First, resolve your default project with your API key:
curl -s http://localhost:8000/api/me/context \
  -H "X-API-Key: dkr_..."
Call project‑scoped endpoints with project_id:
curl -s "http://localhost:8000/api/projects/$PROJECT_ID/prompts" \
  -H "X-API-Key: dkr_..."

Manage API Keys (CRUD)

# Create
curl -s -X POST "http://localhost:8000/api/projects/$PROJECT_ID/api-keys" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Prod Key", "expires_in_days": 365}'

# List (X-API-Key or JWT)
curl -s "http://localhost:8000/api/projects/$PROJECT_ID/api-keys" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Get by ID
curl -s "http://localhost:8000/api/projects/$PROJECT_ID/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

# Revoke
curl -s -X DELETE "http://localhost:8000/api/projects/$PROJECT_ID/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

API Key Best Practices

Never commit API keys to version control. Use environment variables:
DAKORA_API_KEY=your-api-key
Access in code:
import os
api_key = os.environ.get("DAKORA_API_KEY")
Generate new keys periodically and revoke old ones to maintain security.
Create different API keys for different services or environments (dev, staging, production).
Track which API keys are being used and when. Disable unused keys.
Limit API keys to specific projects when possible to reduce blast radius if compromised.

JWT Authentication (Clerk)

How It Works

  1. User Signs In - User authenticates with Clerk
  2. JWT Generated - Clerk issues a JWT token
  3. Token Sent - Frontend adds token to request headers
  4. Token Verified - Backend verifies JWT signature with Clerk’s public key
  5. Request Processed - If valid, request is processed with user context

Making Authenticated Requests

The frontend automatically handles JWT injection via the createApiClient() function:
import { createApiClient } from '@/utils/api';

// With authentication
const client = await createApiClient();

// Automatically includes: Authorization: Bearer <token>
const templates = await client.get('/api/templates');

Session Persistence

Clerk SDK automatically handles session persistence:
  • Tokens stored securely in localStorage
  • Tokens refreshed before expiration
  • Session restored on page reload
  • Works across browser tabs

Error Handling

401 Unauthorized

{
  "detail": "Unauthorized - No valid authentication provided"
}
Solutions:
  • Verify your API key is correct (if using API key auth)
  • Check that your JWT token hasn’t expired (if using Clerk)
  • Ensure X-API-Key or Authorization header is set
  • Verify AUTH_REQUIRED is true in backend configuration

403 Forbidden

{
  "detail": "Forbidden - User does not have access to this resource"
}
Solutions:
  • Verify you have access to the project
  • Check that the resource belongs to your project scope
  • Ensure your user role has appropriate permissions

Multi-Tenancy & Scoping

When authentication is enabled, requests are scoped by:
  • User ID - From JWT token (Clerk) or API key owner
  • Project ID - Stored with user or API key
This means:
  • Users only see their own templates and resources
  • Projects are isolated by default
  • Cross-tenant access is prevented automatically
Example:
# Storage is automatically scoped
storage_prefix = f"users/{user_id}/projects/{project_id}"
# Templates stored at: users/user123/projects/proj456/templates/...

Testing with Authentication

Using TestClient (Backend)

from fastapi.testclient import TestClient
from dakora_server.main import app

client = TestClient(app)

# With API Key
headers = {"X-API-Key": "test-key"}
response = client.get("/api/templates", headers=headers)
assert response.status_code == 200

# With JWT Token
headers = {"Authorization": "Bearer <token>"}
response = client.get("/api/templates", headers=headers)
assert response.status_code == 200

# Without auth (should fail if AUTH_REQUIRED=true)
response = client.get("/api/templates")
assert response.status_code == 401

Using cURL (Manual)

# Health check (public)
curl http://localhost:8000/api/health

# Resolve project
curl -H "X-API-Key: dkr_..." http://localhost:8000/api/me/context

# List prompts (project‑scoped)
curl -H "X-API-Key: dkr_..." "http://localhost:8000/api/projects/$PROJECT_ID/prompts"

# Invalid key
curl -H "X-API-Key: invalid" http://localhost:8000/api/me/context
# → 401 Unauthorized

Troubleshooting

Issue: Clerk not configured properlySolution:
  1. Verify VITE_CLERK_PUBLISHABLE_KEY is set in studio/.env.local
  2. Ensure key is correct (check Clerk dashboard)
  3. Restart dev server: npm run dev
Issue: Authentication failedSolutions:
  • Check X-API-Key is set correctly (if using API key)
  • Verify JWT token hasn’t expired (if using Clerk)
  • Ensure AUTH_REQUIRED=true in backend config
  • Check browser console for token errors
Issue: Multi-tenancy scoping issueSolution:
  • Verify database stores templates under user scope
  • Check user ID matches between frontend and backend
  • Ensure project ID is properly set in Clerk custom claims
Issue: CLERK_JWT_ISSUER or CLERK_JWKS_URL not setSolution:
  1. Get values from Clerk dashboard
  2. Set in backend .env
  3. Restart backend server

Next Steps