Guides

Authentication

API keys and frontend tokens

Learn how to authenticate with EasyRAG using API keys and frontend tokens.

Two Authentication Methods

EasyRAG offers two ways to authenticate:

  1. API Keys - For backend/server-side applications
  2. Frontend Tokens - For browser/mobile applications

When to Use Each Method

Use API Keys When:

  • Building a backend service
  • Creating server-side integrations
  • Running scripts or cron jobs
  • You have a secure environment to store secrets

✅ API keys have full access to your account

Use Frontend Tokens When:

  • Building a browser-based application
  • Creating a mobile app
  • You need to make API calls from the client-side
  • You want to avoid exposing your API key

✅ Frontend tokens are short-lived and dataset-scoped

API Keys

Getting Your API Key

  1. Log into easyrag.com
  2. Go to SettingsAPI Keys
  3. Click Generate API Key
  4. Copy and save it (shown only once!)

Your API key looks like: sk_abc123xyz...

Using API Keys

Include your API key in the Authorization header:

bash
curl https://api.easyrag.com/v1/files?datasetId=my-dataset \ -H "Authorization: Bearer sk_abc123xyz..."

Or use the custom header:

bash
curl https://api.easyrag.com/v1/files?datasetId=my-dataset \ -H "x-easyrag-key: sk_abc123xyz..."

JavaScript Example

javascript
const apiKey = process.env.EASYRAG_API_KEY; const response = await fetch('https://api.easyrag.com/v1/files?datasetId=my-dataset', { headers: { 'Authorization': `Bearer ${apiKey}` } });

Security Best Practices

✅ DO:

  • Store API keys in environment variables
  • Use different keys for dev/staging/production
  • Rotate keys periodically
  • Keep keys on the server-side only

❌ DON'T:

  • Commit API keys to Git
  • Expose API keys in frontend code
  • Share API keys publicly
  • Hardcode API keys in your source code
javascript
// ❌ BAD: Hardcoded in frontend const apiKey = 'sk_abc123xyz...'; // ✅ GOOD: Server-side only // backend.js const apiKey = process.env.EASYRAG_API_KEY;

Frontend Tokens

Frontend tokens solve the problem: "How do I use EasyRAG from my frontend without exposing my API key?"

How It Works

1. User logs into your app
   ↓
2. Your backend verifies the user
   ↓
3. Your backend calls EasyRAG to generate a token
   ↓
4. You send the token to your frontend
   ↓
5. Frontend uses token for API calls

Token Properties

  • Short-lived: Max 24 hours (default: 1 hour)
  • Dataset-scoped: Only works with one dataset
  • Safe for browsers: Can be exposed in client-side code
  • Generated server-side: Requires API key to create

Creating a Frontend Token

Endpoint: POST /v1/tokens/create

Requirements:

  • Must use API key (tokens cannot create tokens)
  • Must specify a datasetId
  • Optionally specify ttlSeconds (max 86400)

Request

bash
curl -X POST https://api.easyrag.com/v1/tokens/create \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "datasetId": "user-123-docs", "ttlSeconds": 3600 }'

Response

json
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600 }

Complete Flow Example

Here's how to implement this in your app:

Backend (Node.js/Express)

javascript
// backend/routes/token.js app.post('/api/get-easyrag-token', authenticateUser, async (req, res) => { const userId = req.user.id; const { datasetId } = req.body; // 1. Verify user owns this dataset (your logic) const hasAccess = await checkUserDatasetAccess(userId, datasetId); if (!hasAccess) { return res.status(403).json({ error: 'Access denied' }); } // 2. Generate token from EasyRAG const response = await fetch('https://api.easyrag.com/v1/tokens/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.EASYRAG_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId, ttlSeconds: 3600 // 1 hour }) }); const { token, expiresIn } = await response.json(); // 3. Send token to frontend res.json({ token, expiresIn }); });

Frontend (React)

javascript
import { useState, useEffect } from 'react'; function useEasyRAGToken(datasetId) { const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchToken() { try { // Call YOUR backend to get a token const response = await fetch('/api/get-easyrag-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', // Send cookies body: JSON.stringify({ datasetId }) }); const { token, expiresIn } = await response.json(); setToken(token); // Refresh token before it expires setTimeout(fetchToken, (expiresIn - 60) * 1000); } catch (error) { console.error('Failed to get token:', error); } finally { setLoading(false); } } fetchToken(); }, [datasetId]); return { token, loading }; } // Usage in your component function DocumentUpload({ datasetId }) { const { token, loading } = useEasyRAGToken(datasetId); const uploadFile = async (file) => { if (!token) return; const formData = new FormData(); formData.append('file', file); // datasetId is optional - token contains it const response = await fetch('https://api.easyrag.com/v1/files/upload', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` // Safe to use in browser! }, body: formData }); return await response.json(); }; if (loading) return <div>Loading...</div>; return <FileUploadUI onUpload={uploadFile} />; }

Using Frontend Tokens

Once you have a token, use it like an API key:

javascript
const response = await fetch('https://api.easyrag.com/v1/search', { method: 'POST', headers: { 'Authorization': `Bearer ${frontendToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ // datasetId is optional - token includes it question: 'What is the refund policy?' }) });

Dataset Scoping

Frontend tokens are locked to a specific dataset:

javascript
// Token was created for "project-a" const token = await createToken('project-a'); // ✅ Works: Same dataset await uploadFile(token, 'project-a', file); await search(token, 'project-a', query); // ❌ Fails with 403: Different dataset await uploadFile(token, 'project-b', file); // Error: "datasetId mismatch between token and request"

Optional datasetId

When using a frontend token, you can omit the datasetId parameter:

javascript
// Both are equivalent with a frontend token: // Option 1: Omit datasetId (token provides it) await fetch('https://api.easyrag.com/v1/search', { headers: { 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ question: 'hello' }) }); // Option 2: Include matching datasetId await fetch('https://api.easyrag.com/v1/search', { headers: { 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ datasetId: 'project-a', // must match token question: 'hello' }) });

Multi-Tenant Patterns

Pattern 1: Dataset Per User (Recommended)

Create a unique dataset for each user:

javascript
// Backend generates token const datasetId = `user-${userId}`; const response = await fetch('https://api.easyrag.com/v1/tokens/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.EASYRAG_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId, // "user-123" ttlSeconds: 3600 }) });

Benefits:

  • Complete data isolation
  • Simple security model
  • No need for metadata filters

Pattern 2: Shared Dataset with Filters

Use one dataset with metadata filtering:

javascript
// Upload with userId in metadata await upload('shared-dataset', file, { metadata: { [file.name]: { userId: currentUserId } } }); // Search with user filter await search('shared-dataset', question, { filters: [ { key: 'userId', match: { value: currentUserId } } ] });

Benefits:

  • Fewer datasets to manage
  • Good for shared data scenarios

Drawbacks:

  • Must remember to apply filters everywhere
  • More complex security model

Token Lifetime Recommendations

Choose appropriate token lifetimes based on your use case:

Use CaseRecommended TTLReason
Single file upload300s (5 min)Just long enough for upload
Chat session3600s (1 hour)Typical conversation length
Mobile app14400s (4 hours)Longer session time
Admin panel86400s (24 hours)All-day access
javascript
// Short-lived for quick operations const uploadToken = await createToken(datasetId, 300); // 5 min // Longer-lived for sessions const chatToken = await createToken(datasetId, 3600); // 1 hour

Error Responses

401 Unauthorized

json
{ "error": "Missing API key or token" }

Fix: Include Authorization: Bearer YOUR_KEY_OR_TOKEN header

403 Forbidden

json
{ "error": "datasetId mismatch between token and request" }

Fix: Ensure the datasetId in your request matches the token's dataset

"Missing API key" (when creating tokens)

json
{ "error": "Missing API key" }

Fix: The /v1/tokens/create endpoint only accepts API keys, not frontend tokens

Security Checklist

Before deploying to production:

  • ✅ API keys stored in environment variables
  • ✅ Frontend tokens generated server-side only
  • ✅ User authentication before token generation
  • ✅ Dataset access control in your app
  • ✅ Appropriate token TTLs
  • ✅ HTTPS enabled
  • ❌ No API keys in frontend code
  • ❌ No keys committed to Git
  • ❌ No keys in logs

Rate Limits

Rate limits apply per customer (not per key/token):

  • Uploads: 100 files/minute
  • Queries: 1000 requests/minute

Both API keys and frontend tokens share these limits.

Need Help?