Authentication
The Luffa API uses API keys to authenticate requests. You can generate and manage your API keys from your dashboard.
API Keys
API keys are the primary method for authenticating with the Luffa API. Include your API key in the Authorization
header of each request.
Getting Your API Key
- Log in to your Luffa dashboard
- Navigate to Settings > API Keys
- Click Create New API Key
- Give your key a descriptive name
- Copy the generated key (you won't be able to see it again)
Using API Keys
Include your API key in the Authorization
header:
curl -H "Authorization: Bearer luffa_sk_1234567890abcdef" \
https://api.luffa.dev/v1/documents
const response = await fetch('https://api.luffa.dev/v1/documents', {
headers: {
'Authorization': 'Bearer luffa_sk_1234567890abcdef',
'Content-Type': 'application/json'
}
})
import requests
headers = {
'Authorization': 'Bearer luffa_sk_1234567890abcdef',
'Content-Type': 'application/json'
}
response = requests.get('https://api.luffa.dev/v1/documents', headers=headers)
API Key Types
Secret Keys (luffa_sk_
)
- Use case: Server-side applications
- Permissions: Full access to your account
- Security: Never expose in client-side code
Public Keys (luffa_pk_
)
- Use case: Client-side applications
- Permissions: Read-only access to public resources
- Security: Safe to include in frontend code
Rate Limiting
API keys are subject to rate limits based on your plan:
Plan | Requests per Hour | Burst Limit |
---|---|---|
Free | 1,000 | 100 |
Pro | 10,000 | 1,000 |
Enterprise | Custom | Custom |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
X-RateLimit-Retry-After: 3600
Error Responses
401 Unauthorized
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Invalid API key provided",
"docs_url": "https://docs.luffa.dev/api/authentication"
}
}
403 Forbidden
{
"error": {
"type": "permission_error",
"code": "insufficient_permissions",
"message": "API key does not have permission for this operation",
"docs_url": "https://docs.luffa.dev/api/authentication"
}
}
429 Rate Limited
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "API rate limit exceeded",
"retry_after": 3600,
"docs_url": "https://docs.luffa.dev/api/authentication"
}
}
Best Practices
Key Management
DO:
- ✅ Store API keys as environment variables
- ✅ Use different keys for different environments
- ✅ Rotate keys regularly (quarterly recommended)
- ✅ Delete unused keys immediately
- ✅ Use minimal permissions for each key
DON'T:
- ❌ Commit API keys to version control
- ❌ Share keys via email or chat
- ❌ Use production keys in development
- ❌ Log API keys in application logs
- ❌ Hardcode keys in client-side code
Environment Variables
# .env.local
LUFFA_API_KEY=luffa_sk_1234567890abcdef
LUFFA_API_BASE_URL=https://api.luffa.dev/v1
# For different environments
LUFFA_API_KEY_DEV=luffa_sk_dev_1234567890abcdef
LUFFA_API_KEY_PROD=luffa_sk_prod_1234567890abcdef
Error Handling
async function callLuffaAPI(endpoint, options = {}) {
try {
const response = await fetch(`https://api.luffa.dev/v1${endpoint}`, {
headers: {
'Authorization': `Bearer ${process.env.LUFFA_API_KEY}`,
'Content-Type': 'application/json',
...options.headers
},
...options
})
if (!response.ok) {
const error = await response.json()
throw new LuffaAPIError(error, response.status)
}
return await response.json()
} catch (error) {
if (error.status === 401) {
// Handle authentication error
console.error('Invalid API key')
} else if (error.status === 429) {
// Handle rate limiting
const retryAfter = error.headers.get('retry-after')
console.error(`Rate limited. Retry after ${retryAfter} seconds`)
}
throw error
}
}
OAuth 2.0 (Enterprise)
For enterprise customers, Luffa supports OAuth 2.0 for user authentication.
Authorization Code Flow
- Redirect to Authorization
https://auth.luffa.dev/oauth/authorize?
client_id=your_client_id&
redirect_uri=https://yourapp.com/callback&
scope=read:documents+write:documents&
response_type=code&
state=random_state_string
- Exchange Code for Token
curl -X POST https://auth.luffa.dev/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=your_client_id" \
-d "client_secret=your_client_secret" \
-d "code=auth_code_from_callback" \
-d "redirect_uri=https://yourapp.com/callback"
- Use Access Token
curl -H "Authorization: Bearer oauth_access_token" \
https://api.luffa.dev/v1/user/documents
Webhooks Authentication
Webhooks include a signature header for verification:
const crypto = require('crypto')
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)
}
// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-luffa-signature']
const isValid = verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET)
if (!isValid) {
return res.status(401).send('Invalid signature')
}
// Process webhook
res.status(200).send('OK')
})
Testing Authentication
Use our test endpoints to verify your authentication setup:
# Test your API key
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.luffa.dev/v1/auth/test
# Expected response
{
"authenticated": true,
"key_id": "key_1234567890",
"permissions": ["read:documents", "write:documents"],
"rate_limit": {
"limit": 1000,
"remaining": 999,
"reset": 1640995200
}
}
Need Help?
- Security concerns: security@luffa.dev
- API support: support@luffa.dev
- Documentation: Discord community