An extension to Django OAuth Toolkit that adds support for OAuth 2.0 Dynamic Client Registration as defined in RFC 7591.
- ✅ RFC 7591 Compliant: Full implementation of OAuth 2.0 Dynamic Client Registration
- ✅ Open Registration Mode: No authentication required for client registration
- ✅ Comprehensive Validation: Validates client metadata, redirect URIs, and grant types
- ✅ Django OAuth Toolkit Integration: Seamlessly works with existing DOT applications
- ✅ Flexible Grant Type Support: Authorization Code, Implicit, Client Credentials, and more
- ✅ Error Handling: RFC-compliant error responses
- ✅ Security Focused: Built-in validations and configurable restrictions
Install the package using pip:
pip install django-oauth-toolkit-dcr- Python 3.10+
- Django 4.0+
- django-oauth-toolkit 3.0.1+
Add the package to your INSTALLED_APPS:
INSTALLED_APPS = [
    # ... your other apps
    'oauth2_provider',
    'oauth_dcr',
]Add the Dynamic Client Registration endpoint to your URL configuration:
# urls.py
from django.urls import path, include
from oauth_dcr.views import DynamicClientRegistrationView
urlpatterns = [
    # Your existing OAuth2 URLs
    path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
    
    # Dynamic Client Registration endpoint
    path('o/register/', DynamicClientRegistrationView.as_view(), name='oauth2_dcr'),
]Make sure your Django OAuth Toolkit migrations are up to date:
python manage.py migrateClients can register themselves by sending a POST request to the registration endpoint:
curl -X POST https://your-server.com/o/register/ \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My Amazing App",
    "redirect_uris": [
      "https://myapp.com/oauth/callback",
      "https://myapp.com/oauth/callback2"
    ],
    "grant_types": ["authorization_code"],
    "response_types": ["code"],
    "scope": "read write",
    "client_uri": "https://myapp.com",
    "contacts": ["[email protected]"]
  }'{
  "client_id": "AbCdEf123456",
  "client_secret": "secret_AbCdEf123456789",
  "client_id_issued_at": 1625097600,
  "client_name": "My Amazing App",
  "redirect_uris": [
    "https://myapp.com/oauth/callback",
    "https://myapp.com/oauth/callback2"
  ],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "client_secret_basic"
}Invalid Grant Type:
{
  "error": "invalid_client_metadata",
  "error_description": "Grant type 'password' is not allowed for dynamic registration"
}Missing Redirect URIs:
{
  "error": "invalid_client_metadata",
  "error_description": "redirect_uris required for authorization code grants"
}HTTPS Required:
{
  "error": "invalid_client_metadata",
  "error_description": "HTTPS required for redirect URIs in production: http://example.com/callback"
}The following client metadata parameters are supported:
| Parameter | Required | Description | 
|---|---|---|
| client_name | No | Human-readable name for the client | 
| redirect_uris | Conditional* | Array of redirect URIs | 
| grant_types | No | Array of grant types (default: ["authorization_code"]) | 
| response_types | No | Array of response types | 
| scope | No | Space-separated list of scopes | 
| client_uri | No | URL of the client's homepage | 
| contacts | No | Array of contact email addresses | 
| token_endpoint_auth_method | No | Token endpoint authentication method | 
*Required for authorization_code, implicit, and hybrid flows.
All RFC 7591 compliant grant types are supported:
- authorization_code- Authorization Code Grant ✅ (enabled by default)
- implicit- Implicit Grant ✅ (enabled by default)
- refresh_token- Refresh Token Grant ✅ (enabled by default)
- password- Resource Owner Password Credentials Grant (- ⚠️ disabled by default - security risk)
- client_credentials- Client Credentials Grant (- ⚠️ disabled by default - security risk)
- urn:ietf:params:oauth:grant-type:jwt-bearer- JWT Bearer Grant (- ⚠️ disabled by default - security risk)
- urn:ietf:params:oauth:grant-type:saml2-bearer- SAML 2.0 Bearer Grant (- ⚠️ disabled by default - security risk)
The extension respects your existing Django OAuth Toolkit configuration:
# settings.py
OAUTH2_PROVIDER = {
    'ALLOWED_REDIRECT_URI_SCHEMES': ['https', 'http'],  # Used for validation
    'OIDC_RSA_PRIVATE_KEY': 'your-rsa-key',  # For OIDC support
    # ... other settings
}Configure DCR-specific settings for enhanced security:
# settings.py
OAUTH_DCR_SETTINGS = {
    # Grant types allowed for dynamic registration (RFC 7591 safe defaults)
    'ALLOWED_GRANT_TYPES': [
        'authorization_code',  # Safe for open registration
        'implicit',           # Part of RFC 7591 (deprecated in OAuth 2.1)
        'refresh_token',      # Safe - used for token renewal
        # 'password',          # SECURITY RISK: Allows credential collection
        # 'client_credentials', # SECURITY RISK: Machine-to-machine access
        # 'urn:ietf:params:oauth:grant-type:jwt-bearer',    # SECURITY RISK
        # 'urn:ietf:params:oauth:grant-type:saml2-bearer',  # SECURITY RISK
    ],
    
    # Require HTTPS for redirect URIs in production (default: True in production)
    'REQUIRE_HTTPS_REDIRECT_URIS': True,
}| Grant Type | Security Risk | Why Restricted by Default | 
|---|---|---|
| password | HIGH | Allows any client to collect user credentials | 
| client_credentials | HIGH | Enables machine-to-machine access without user consent | 
| jwt-bearer | MEDIUM | Can potentially bypass normal authentication flows | 
| saml2-bearer | MEDIUM | Can potentially bypass normal authentication flows | 
| authorization_code | LOW | Secure with proper PKCE implementation ✅ | 
| implicit | MEDIUM | Deprecated due to token exposure, but part of RFC 7591 ✅ | 
| refresh_token | LOW | Safe token renewal mechanism ✅ | 
Since this implements "open" registration mode, the following security measures are strongly recommended:
- Grant Type Restrictions: Only allow safe grant types (default configuration)
- HTTPS Enforcement: Require HTTPS for redirect URIs in production (default)
- Rate Limiting: Use Django rate limiting middleware
- Monitoring: Log all registration attempts
- Cleanup: Implement periodic cleanup of unused clients
- Network Security: Consider IP allowlisting or VPN requirements
You can extend the view to add custom validation:
from oauth_dcr.views import DynamicClientRegistrationView
from django.core.exceptions import ValidationError
class CustomDCRView(DynamicClientRegistrationView):
    def _validate_client_metadata(self, metadata):
        # Call parent validation first
        processed = super()._validate_client_metadata(metadata)
        
        # Add custom validation
        if 'client_name' in metadata:
            if 'forbidden' in metadata['client_name'].lower():
                raise ValidationError("Client name contains forbidden words")
        
        return processedUsing django-ratelimit:
from django_ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
@method_decorator(ratelimit(key='ip', rate='10/h', method='POST'), name='post')
class RateLimitedDCRView(DynamicClientRegistrationView):
    passMain view class that handles client registration requests.
- post(request)- Handle registration requests
- _validate_client_metadata(metadata)- Override for custom validation
- _create_application(metadata)- Override for custom application creation
Run the tests:
pytestContributions are welcome! Please feel free to submit a Pull Request.
Contributions are particularly welcome to implement:
- RFC 7592 Dynamic Client Registration Management Protocol (client configuration endpoint, update/delete operations)
- Additional registration modes (protected, authenticated, administrative registration beyond the current open mode)
- Enhanced security features (rate limiting, audit logging, client attestation)
- OpenID Connect Dynamic Client Registration support
- Security Measures rate limiting
- Fork the repository
- Create your feature branch (git checkout -b feature/amazing-feature)
- Commit your changes (git commit -m 'Add some amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Django OAuth Toolkit - The base OAuth 2.0 implementation
- oauthlib - The underlying OAuth library
If you encounter any issues or have questions:
- Check the Issues page
- Create a new issue with detailed information
- For general OAuth questions, refer to the Django OAuth Toolkit documentation
- Initial implementation of RFC 7591 Dynamic Client Registration
- Support for open registration mode
- Comprehensive client metadata validation
- Integration with Django OAuth Toolkit Application model