API Keys
API keys provide authentication for automation, scripts, and third-party applications like OPDS readers.
Key Concepts
- API keys are scoped to permissions - Each key has a specific set of permissions
- Keys cannot exceed user permissions - You can only grant permissions you have
- Keys are constrained at request time - If your role changes, your keys are automatically limited
- Keys can have expiration dates - Optional time-limited access
Creating API Keys
Via Web Interface
- Go to Settings > Profile > API Keys
- Click Create API Key
- Enter a descriptive name
- Select a permission preset or customize:
- Full Access - All permissions you have
- Read Only - Browse and read content
- OPDS/Reader Apps - Minimal read-only access
- Custom - Select individual permissions
- Optionally set an expiration date
- Click Create
- Copy the key immediately - it's only shown once!
Via API
curl -X POST http://localhost:8080/api/v1/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Automation Script",
"permissions": ["LibrariesRead", "BooksRead", "PagesRead"]
}'
Response:
{
"id": "uuid",
"name": "Automation Script",
"key": "codex_abc12345_secretpart123456789",
"key_prefix": "codex_abc12345",
"permissions": ["LibrariesRead", "BooksRead", "PagesRead"],
"expires_at": null,
"created_at": "2024-01-15T10:00:00Z"
}
The full API key is only shown once! Store it securely immediately. If lost, you must create a new key.
Permission Constraints
You Can Only Grant What You Have
API keys are constrained by your effective permissions:
Token Effective Permissions = (Your Role ∪ Your Custom) ∩ Token Requested
Example: A Maintainer (15 permissions) cannot create a key with UsersRead because that permission is Admin-only.
Keys Are Validated at Request Time
If your role is downgraded, your existing keys are automatically constrained:
- Admin creates key with
UsersReadpermission - Admin is demoted to Maintainer
- Key requests to
/api/v1/usersnow fail -UsersReadis no longer in the user's effective permissions
This ensures keys never grant more access than the user currently has.
No Permissions = User's Full Access
If you don't specify permissions when creating a key, it inherits your full effective permissions:
# Creates key with all your permissions
curl -X POST http://localhost:8080/api/v1/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Full Access Key"}'
Using API Keys
X-API-Key Header (Recommended)
curl -H "X-API-Key: codex_abc12345_secretpart" \
http://localhost:8080/api/v1/libraries
Bearer Token
curl -H "Authorization: Bearer codex_abc12345_secretpart" \
http://localhost:8080/api/v1/libraries
Basic Auth (for OPDS readers)
Many OPDS reader apps only support Basic Auth:
Username: api
Password: codex_abc12345_secretpart
Or with curl:
curl -u "api:codex_abc12345_secretpart" \
http://localhost:8080/opds/v1.2/catalog
Key Format
API keys follow the format: codex_<prefix>_<secret>
| Part | Description |
|---|---|
codex_ | Fixed prefix identifying Codex keys |
<prefix> | 8-character identifier for quick lookup |
<secret> | Random secret (hashed in database) |
The prefix is stored in plaintext for lookup, but the secret is hashed - Codex cannot recover lost keys.
Permission Presets
OPDS / Reader Apps
Minimal permissions for read-only access:
{
"name": "OPDS Reader",
"permissions": ["LibrariesRead", "SeriesRead", "BooksRead", "PagesRead"]
}
Automation Script
For scripts that trigger scans and monitor progress:
{
"name": "Scanner Script",
"permissions": [
"LibrariesRead",
"LibrariesWrite",
"TasksRead",
"TasksWrite"
]
}
Mobile App
Full reading experience with progress tracking:
{
"name": "Mobile App",
"permissions": [
"LibrariesRead",
"SeriesRead",
"BooksRead",
"BooksWrite",
"PagesRead"
]
}
Metadata Manager
For tools that update metadata:
{
"name": "Metadata Tool",
"permissions": [
"LibrariesRead",
"SeriesRead",
"SeriesWrite",
"BooksRead",
"BooksWrite"
]
}
Managing API Keys
List Your Keys
curl http://localhost:8080/api/v1/api-keys \
-H "Authorization: Bearer $TOKEN"
Response shows key metadata (not the secret):
[
{
"id": "uuid",
"name": "OPDS Reader",
"key_prefix": "codex_abc12345",
"permissions": ["LibrariesRead", "BooksRead"],
"last_used_at": "2024-01-15T12:30:00Z",
"expires_at": null,
"created_at": "2024-01-01T10:00:00Z"
}
]
Revoke a Key
curl -X DELETE http://localhost:8080/api/v1/api-keys/{id} \
-H "Authorization: Bearer $TOKEN"
Revoked keys are immediately invalid.
Key with Expiration
curl -X POST http://localhost:8080/api/v1/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Temporary Access",
"permissions": ["LibrariesRead", "BooksRead"],
"expires_at": "2024-02-01T00:00:00Z"
}'
Expired keys are automatically rejected.
Best Practices
- Use minimal permissions - Only grant what the application needs
- Descriptive names - Name keys by purpose (e.g., "Panels iOS App", "Scan Script")
- Separate keys per app - Don't share keys between applications
- Set expiration dates - For temporary or guest access
- Monitor last_used_at - Identify unused keys for cleanup
- Rotate periodically - Create new keys and revoke old ones
- Never commit to VCS - Use environment variables or secret managers
- Revoke compromised keys - Delete immediately if exposed
Troubleshooting
Key Not Working
- Check the full key - Ensure no truncation or extra whitespace
- Verify not revoked - Check key still exists in your profile
- Check expiration - Key may have expired
- Try different header - Some clients handle headers differently
Permission Denied
- Check key permissions - View key in profile to see its permissions
- Check your role - Your role may have changed since key creation
- Verify endpoint permissions - Confirm which permission the endpoint requires
"Invalid API key format"
The key must start with codex_ and have the correct structure. Verify you're using the complete key.