Reusable Django app for secure API key authentication and management. This package provides encrypted API key storage with support for both REST Framework and GraphQL authentication.
- Encrypted API Key Storage: API keys are encrypted using AES-SIV encryption before being stored in the database
- REST Framework Authentication: Built-in authentication classes for Django REST Framework
- GraphQL Authentication: Middleware and consumer classes for GraphQL WebSocket authentication
- Permission Classes: Ready-to-use permission classes for API key validation
- Admin Interface: Django admin integration with automatic API key generation
- Management Commands: CLI tools for encryption key generation and rotation
- Expiration Support: Optional expiry dates for API keys with automatic validation
- Key Rotation: Support for rotating encryption keys without losing existing API keys
Install in your environment:
pip install baseapp-backend[api_key]And run provision or manually pip install -r requirements/base.ext
If you want to develop, install using this other guide.
Add baseapp_api_key to your project's INSTALLED_APPS:
INSTALLED_APPS = [
# ... other apps
'baseapp_api_key',
]Add the required settings to your Django settings:
# Required: Encryption key for API keys (generate using management command)
BA_API_KEY_ENCRYPTION_KEY = env("BA_API_KEY_ENCRYPTION_KEY")
# Required: HTTP header name for API key authentication
BA_API_KEY_REQUEST_HEADER = env("BA_API_KEY_REQUEST_HEADER", default="HTTP_API_KEY")Generate an encryption key using the management command:
python manage.py api_key --model baseapp_api_key.APIKey --generate_encryption_keyAPI keys can be created through the Django admin interface or programmatically:
from baseapp_api_key.models import APIKey
# Create an API key for a user
api_key = APIKey.objects.create(
user=user,
name="My API Key",
expiry_date=None # Optional expiry date
)
# The encrypted API key is automatically generated and storedUse the provided authentication class in your Django REST Framework views:
from rest_framework.views import APIView
from baseapp_api_key.rest_framework.authentication import APIKeyAuthentication
from baseapp_api_key.rest_framework.permissions import HasAPIKey
class MyAPIView(APIView):
authentication_classes = [APIKeyAuthentication]
permission_classes = [HasAPIKey] # or use IsAuthenticated
def get(self, request):
# User is authenticated via API key
return Response({'user': request.user.username})For GraphQL WebSocket authentication, use the provided consumer:
# routing.py
from baseapp_api_key.graphql.consumers import GraphqlWsAPIKeyAuthenticatedConsumer
websocket_urlpatterns = [
path("graphql/", GraphqlWsAPIKeyAuthenticatedConsumer.as_asgi()),
]For GraphQL HTTP requests, use the middleware:
# In your GraphQL schema
from baseapp_api_key.graphql.middleware import APIKeyAuthentication
schema = graphene.Schema(
query=Query,
mutation=Mutation,
middleware=[APIKeyAuthentication()]
)Include the API key in the configured header:
# Using curl
curl -H "API-Key: BA-your-64-character-api-key-here" \
https://your-api.com/api/endpoint/
# Using Python requests
import requests
headers = {
'API-Key': 'BA-your-64-character-api-key-here'
}
response = requests.get('https://your-api.com/api/endpoint/', headers=headers)Generate a new encryption key for your environment:
python manage.py api_key --model baseapp_api_key.APIKey --generate_encryption_keyRotate existing encryption keys (useful for security key rotation):
python manage.py api_key --model baseapp_api_key.APIKey --rotate_encryption_key OLD_KEY NEW_KEYThis command will:
- Decrypt all existing API keys using the old key
- Re-encrypt them using the new key
- Update the database with the newly encrypted values
You can extend the base API key model for your specific needs:
from baseapp_api_key.models import BaseAPIKey
class CustomAPIKey(BaseAPIKey):
# Add custom fields
description = models.TextField(blank=True)
permissions = models.JSONField(default=dict)
# Use custom prefix
objects = BaseAPIKeyManager(api_key_prefix="CUSTOM")
class Meta(BaseAPIKey.Meta):
abstract = FalseThen create corresponding authentication classes:
from baseapp_api_key.rest_framework.authentication import BaseAPIKeyAuthentication
class CustomAPIKeyAuthentication(BaseAPIKeyAuthentication):
APIKeyModel = CustomAPIKey- API keys are encrypted using AES-SIV (Synthetic Initialization Vector) encryption
- Only encrypted values are stored in the database
- Original API keys are never stored in plaintext
- API keys follow the format:
{PREFIX}-{64-character-random-string} - Default prefix is "BA" but can be customized per model
- Keys are generated using Django's cryptographically secure random string generator
- Optional expiry dates with automatic validation
- Expired keys are rejected during authentication
- QuerySet methods automatically filter expired keys
- Supports rotating encryption keys without losing existing API keys
- Management command handles the rotation process safely
- Maintains data integrity during key rotation
The package provides a Django admin interface for managing API keys:
- List View: Shows API key ID, user, name, and expiration status
- Create/Edit: Automatically generates encrypted API keys on creation
- Security: Displays the unencrypted API key only once during creation
- User Default: Sets the current admin user as the default key owner
The package includes comprehensive test coverage:
# Run API key tests
python manage.py test baseapp_api_key
# Run with coverage
coverage run --source='.' manage.py test baseapp_api_key
coverage reportClone the project inside your project's backend dir:
git clone git@github.com:silverlogic/baseapp-backend.gitAnd manually install the package:
pip install -e baseapp-backend/baseapp_api_keyThe -e flag will make it so any changes you make in the cloned repo files will affect the project.
Abstract base model for API keys.
Fields:
user: ForeignKey to AUTH_USER_MODELname: CharField for API key identificationencrypted_api_key: BinaryField storing encrypted keyexpiry_date: Optional DateField for key expirationcreated: Auto-generated creation timestampmodified: Auto-generated modification timestamp
Properties:
is_expired: Boolean indicating if the key has expired
Concrete implementation of BaseAPIKey ready for use.
Custom manager providing encryption and key management functionality.
Methods:
generate_encryption_key(): Generate a new AES-SIV encryption keygenerate_unencrypted_api_key(): Generate a new unencrypted API key stringencrypt(value, encryption_key=None): Encrypt a value using AES-SIVdecrypt(encrypted_value, encryption_key=None): Decrypt an encrypted valuerotate_encryption_key(old_key, new_key): Rotate encryption keys for all records
BaseAPIKeyAuthentication: Abstract authentication classAPIKeyAuthentication: Concrete implementation for APIKey model
APIKeyAuthentication: Middleware for GraphQL HTTP requestsBaseGraphqlWsAPIKeyAuthenticatedConsumer: WebSocket consumer base classGraphqlWsAPIKeyAuthenticatedConsumer: Concrete WebSocket consumer
BaseHasAPIKey: Abstract permission classHasAPIKey: Concrete permission class for APIKey validation