Guides
API keys and frontend tokens
Learn how to authenticate with EasyRAG using API keys and frontend tokens.
EasyRAG offers two ways to authenticate:
✅ API keys have full access to your account
✅ Frontend tokens are short-lived and dataset-scoped
Your API key looks like: sk_abc123xyz...
Include your API key in the Authorization header:
bashcurl https://api.easyrag.com/v1/files?datasetId=my-dataset \ -H "Authorization: Bearer sk_abc123xyz..."
Or use the custom header:
bashcurl https://api.easyrag.com/v1/files?datasetId=my-dataset \ -H "x-easyrag-key: sk_abc123xyz..."
javascriptconst apiKey = process.env.EASYRAG_API_KEY; const response = await fetch('https://api.easyrag.com/v1/files?datasetId=my-dataset', { headers: { 'Authorization': `Bearer ${apiKey}` } });
✅ DO:
❌ DON'T:
javascript// ❌ BAD: Hardcoded in frontend const apiKey = 'sk_abc123xyz...'; // ✅ GOOD: Server-side only // backend.js const apiKey = process.env.EASYRAG_API_KEY;
Frontend tokens solve the problem: "How do I use EasyRAG from my frontend without exposing my API key?"
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
Endpoint: POST /v1/tokens/create
Requirements:
datasetIdttlSeconds (max 86400)bashcurl -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 }'
json{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600 }
Here's how to implement this in your app:
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 }); });
javascriptimport { 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} />; }
Once you have a token, use it like an API key:
javascriptconst 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?' }) });
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"
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' }) });
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:
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:
Drawbacks:
Choose appropriate token lifetimes based on your use case:
| Use Case | Recommended TTL | Reason |
|---|---|---|
| Single file upload | 300s (5 min) | Just long enough for upload |
| Chat session | 3600s (1 hour) | Typical conversation length |
| Mobile app | 14400s (4 hours) | Longer session time |
| Admin panel | 86400s (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
json{ "error": "Missing API key or token" }
Fix: Include Authorization: Bearer YOUR_KEY_OR_TOKEN header
json{ "error": "datasetId mismatch between token and request" }
Fix: Ensure the datasetId in your request matches the token's dataset
json{ "error": "Missing API key" }
Fix: The /v1/tokens/create endpoint only accepts API keys, not frontend tokens
Before deploying to production:
Rate limits apply per customer (not per key/token):
Both API keys and frontend tokens share these limits.