django-tenant-apikeys¶
Multi-tenant API key authentication for Django.
django-tenant-apikeys is a Django library for issuing API keys that belong
to a tenant — an organization, account, or workspace — rather than to a
single User. It covers the part of Django API key authentication that
TokenAuthentication and session auth don't: a key is generated once, shown
once, stored as a hash, resolved to its tenant on every request, and can
carry its own scopes, IP restrictions, and rate limit, independent of every
other key that tenant has issued.
It ships a small framework-agnostic core plus first-class integrations for Django REST Framework and Django Ninja.
Who this is for¶
You're building a Django API that other systems call programmatically — partner integrations, internal services, customer-facing automation — and more than one tenant uses your API. If a single tenant issues more than one key (a read-only reporting integration and a full-access internal key, say), or if you need to know which tenant and which key made a request without writing that lookup yourself in every view, this is the shape of problem the package solves.
If you're not multi-tenant, or a permission-only gate ("does this request carry a valid key at all") is enough for you, a narrower package like djangorestframework-api-key is probably a better fit — see the comparison in the wiki if you're deciding between the two.
What it actually does¶
- Generates and verifies keys. A key is
secrets-generated, split into a cleartextprefix(for an indexed lookup) and a secret (stored only as a SHA-256 hash). See Authentication. - Resolves the tenant automatically. Subclass one abstract model, add a
tenantforeign key, and both the DRF and Ninja integrations attach it torequest.tenanton every authenticated request. See Multi-tenancy. - Scopes access per key, not per tenant, with exact, namespaced
(
orders:*), and global (*) wildcard matching. See Scopes. - Restricts a key by IP or CIDR network (IPv4 and IPv6). See IP restrictions.
- Rate-limits a key per second/minute/hour/day, backed by Django's cache framework. See Rate limiting.
- Tags a key with an environment (production/staging/development/test) and arbitrary JSON metadata your application defines. See Environments and Metadata.
- Handles the full lifecycle — rotation, revocation, expiration, and throttled last-used tracking. See Key lifecycle.
30 seconds¶
# myapp/models.py
from django.db import models
from django_tenant_apikeys.models import AbstractTenantAPIKey
class Organization(models.Model):
name = models.CharField(max_length=100)
class OrganizationAPIKey(AbstractTenantAPIKey):
tenant = models.ForeignKey(
Organization, related_name="api_keys", on_delete=models.CASCADE
)
instance, raw_key = OrganizationAPIKey.generate_key(
name="CI deploy key",
tenant=org,
scopes=["deployments:write"],
)
print(raw_key) # tak_live_3f9a2c1d.k7pQ2m1v... -- shown once, never stored
# myapp/views.py (Django REST Framework)
from rest_framework.views import APIView
from django_tenant_apikeys.authentication import TenantAPIKeyAuthentication
from django_tenant_apikeys.permissions import HasAPIKeyScope
class DeploymentsView(APIView):
authentication_classes = [TenantAPIKeyAuthentication]
permission_classes = [HasAPIKeyScope]
required_scopes = ["deployments:write"]
def post(self, request):
request.tenant.deployments.create(...) # attached automatically
That's the whole shape of it. Everything else in these docs is what to do once you need more than the basics — scoped API keys across several integrations, IP allowlists, per-key rate limits, or wiring the same key model into Django Ninja instead of (or alongside) DRF.
Where to go next¶
- New to the package? Start with Installation and Quickstart.
- Already have keys authenticating and want to add policies? See Environments, IP restrictions, and Rate limiting.
- Wiring this into an existing DRF or Ninja project? Jump straight to Django REST Framework or Django Ninja.
- Deciding whether to trust this in production? Read Security first.
- Looking for a specific class or function? API reference.
A complete runnable project lives in
examples/simple_saas/
in the repository — clone it, run python manage.py create_demo_key, and
you have a real tenant-scoped key and a working curl command in about a
minute.