Skip to Content
FeaturesModulesgRPC ServerAuthentication

gRPC Authentication

Learn how to secure your gRPC services with API keys.

🎯 Overview

Django-CFG gRPC uses API Key authentication for secure service access:

MethodBest ForManagementLifespan
API KeysServices, CLI tools, webhooks, all use casesDjango AdminLong-lived (configurable)

Security Enhancement

API keys are stored as SHA-256 hashes instead of plaintext. The raw key is shown only once during creation - store it securely!

🔑 API Key Authentication

Concept

API keys are long-lived tokens for machine-to-machine communication:

  • Create keys in Django Admin
  • Each key authenticates as a specific user
  • Can be revoked instantly
  • Usage is tracked automatically

Creating Keys

Via Python (Recommended):

from django_cfg.modules.django_grpc.models import GrpcApiKey # Generate a new API key (returns tuple) api_key, raw_key = GrpcApiKey.generate( name="My Service", user=user, # Optional: associate with Django user ) # IMPORTANT: raw_key is only available during creation! print(f"Save this key: {raw_key}") # Store securely print(f"Key prefix: {api_key.key_prefix}") # For identification

The raw key is only returned during generation. Store it securely - it cannot be retrieved later.

Via Django Admin:

  1. Go to /admin/gRPC API Keys
  2. Click “Add gRPC API Key” or use “Generate New Key” action
  3. Fill in name, user, type, expiration
  4. Save and copy the generated key (shown only once!)

Using Keys

With grpcurl:

grpcurl -H "x-api-key: YOUR_API_KEY" \ localhost:50051 api.users.UserService/GetUser

With Python client:

import grpc # Add API key to metadata metadata = [('x-api-key', 'YOUR_API_KEY')] with grpc.insecure_channel('localhost:50051') as channel: stub = UserServiceStub(channel) response = stub.GetUser(request, metadata=metadata)

In service:

class UserService(BaseService): def UpdateProfile(self, request, context): # Access authenticated user user = context.user # Set by API key auth # Also access the API key used api_key = context.api_key # Which key was used user.bio = request.bio user.save() return UserResponse(...)

Validating Keys Programmatically

from django_cfg.modules.django_grpc.models import GrpcApiKey # Synchronous validation api_key = GrpcApiKey.validate(incoming_key) if api_key: print(f"Valid key: {api_key.name}") print(f"User: {api_key.user}") else: print("Invalid or inactive key") # Async validation (recommended for gRPC services) api_key = await GrpcApiKey.avalidate_key(incoming_key) if not api_key: raise PermissionDenied("Invalid API key")

Development Shortcut

For development, you can use Django’s SECRET_KEY:

# Use SECRET_KEY instead of creating API key grpcurl -H "x-api-key: django-insecure-dev-key..." \ localhost:50051 api.users.UserService/GetUser

Only use SECRET_KEY in development! Disable in production via accept_django_secret_key: False

🔧 Configuration

API Key Settings

# api/config.py from django_cfg import DjangoConfig, GRPCConfig, GRPCAuthConfig class MyConfig(DjangoConfig): grpc = GRPCConfig( enabled=True, enabled_apps=["apps.users"], # Authentication settings auth=GRPCAuthConfig( enabled=True, # Enable authentication require_auth=False, # Allow anonymous by default # API Key settings api_key_header="x-api-key", # Header name accept_django_secret_key=True, # Allow SECRET_KEY (dev only!) # Public methods (no auth needed) public_methods=[ "/grpc.health.v1.Health/Check", ], ), )

Authentication Modes

1. Disabled (Development):

auth=GRPCAuthConfig( enabled=False, # All methods public )

2. Optional Auth (Recommended):

auth=GRPCAuthConfig( enabled=True, require_auth=False, # Some methods can be public api_key_header="x-api-key", accept_django_secret_key=True, # Allow SECRET_KEY for dev )

3. Required Auth (Strict):

auth=GRPCAuthConfig( enabled=True, require_auth=True, # All methods require API key api_key_header="x-api-key", accept_django_secret_key=False, # Production: only DB keys public_methods=[ "/grpc.health.v1.Health/Check", # Except health check ], )

🛡️ Service Authorization

Public Methods

class UserService(BaseService): def GetUser(self, request, context): # No auth required - anyone can call user = User.objects.get(id=request.user_id) return UserResponse(...)

Protected Methods

class UserService(BaseService): def UpdateProfile(self, request, context): # Require authentication user = self.require_user(context) user.bio = request.bio user.save() return UserResponse(...)

Permission Checks

class UserService(BaseService): def DeleteUser(self, request, context): # Require staff permission self.require_staff(context) User.objects.get(id=request.user_id).delete() return Empty()

📊 Monitoring

View Logs

All authenticated requests are logged with:

  • Which user made the request
  • Which API key was used (if applicable)
  • Request duration and status

Django Admin:

/admin/ → gRPC Request Logs

Filter by:

  • User
  • API Key
  • Status (success/error)
  • Date range

Check API Key Usage

Django Admin:

/admin/ → gRPC API Keys

See for each key:

  • Total request count
  • Last used timestamp
  • Status (active/expired/revoked)

🔒 Best Practices

API Keys

DO:

  • Create separate keys for each service
  • Set expiration dates for better security
  • Revoke unused keys regularly
  • Monitor usage in Django Admin
  • Disable accept_django_secret_key in production
  • Use descriptive names (e.g., “Analytics Service”, “Mobile App Backend”)
  • Track usage statistics regularly

DON’T:

  • Share keys between services
  • Use SECRET_KEY in production
  • Hardcode keys in source code
  • Leave expired keys active
  • Create keys without expiration dates in production

📚 Common Patterns

Service-to-Service Communication

# Service A calls Service B # 1. Create API key for Service A in Django Admin # 2. Store key in Service A's environment variables # 3. Service A includes key in metadata # Service A (caller) import os metadata = [('x-api-key', os.getenv('SERVICE_B_API_KEY'))] response = service_b_stub.Method(request, metadata=metadata)

CLI Tools

# Create API key for CLI tool # 1. Go to Django Admin → gRPC API Keys # 2. Create key with type "cli" # 3. Copy key and store securely # Use in CLI tool grpcurl -H "x-api-key: YOUR_CLI_API_KEY" \ localhost:50051 api.users.UserService/GetUser

Webhook Handlers

# Webhook service calling gRPC # 1. Create API key with type "webhook" # 2. Configure webhook handler from django.views.decorators.csrf import csrf_exempt import grpc @csrf_exempt def webhook_handler(request): # Parse webhook data data = json.loads(request.body) # Call gRPC with API key metadata = [('x-api-key', settings.WEBHOOK_GRPC_API_KEY)] with grpc.insecure_channel('localhost:50051') as channel: stub = ServiceStub(channel) response = stub.Method(data, metadata=metadata) return JsonResponse({'status': 'ok'})

Development Testing

# Use Django SECRET_KEY for quick testing # (Only works if accept_django_secret_key=True) from django.conf import settings metadata = [('x-api-key', settings.SECRET_KEY)] response = stub.Method(request, metadata=metadata)

Next Steps:

Last updated on