Django OAuth Toolkit DCR

An extension to Django OAuth Toolkit that adds support for OAuth 2.0 Dynamic Client Registration as defined in RFC 7591.
Features
- ✅ 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
Installation
Install the package using pip:
pip install django-oauth-toolkit-dcr
Requirements
- Python 3.10+
- Django 4.0+
- django-oauth-toolkit 3.0.1+
Quick Start
1. Add to Django Settings
Add the package to your INSTALLED_APPS
:
INSTALLED_APPS = [
'oauth2_provider',
'oauth_dcr',
]
2. Configure URLs
Add the Dynamic Client Registration endpoint to your URL configuration:
from django.urls import path, include
from oauth_dcr.views import DynamicClientRegistrationView
urlpatterns = [
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
path('o/register/', DynamicClientRegistrationView.as_view(), name='oauth2_dcr'),
]
3. Run Migrations
Make sure your Django OAuth Toolkit migrations are up to date:
python manage.py migrate
Usage
Client Registration Request
Clients 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": ["admin@myapp.com"]
}'
Successful Registration Response
{
"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"
}
Error Response Examples
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"
}
Supported Client Metadata
The following client metadata parameters are supported:
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.
Supported Grant Types
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)
Configuration
Django OAuth Toolkit Settings
The extension respects your existing Django OAuth Toolkit configuration:
OAUTH2_PROVIDER = {
'ALLOWED_REDIRECT_URI_SCHEMES': ['https', 'http'],
'OIDC_RSA_PRIVATE_KEY': 'your-rsa-key',
}
Dynamic Client Registration Settings
Configure DCR-specific settings for enhanced security:
OAUTH_DCR_SETTINGS = {
'ALLOWED_GRANT_TYPES': [
'authorization_code',
'implicit',
'refresh_token',
],
'REQUIRE_HTTPS_REDIRECT_URIS': True,
}
Security Rationale for Grant Type Restrictions
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 ✅ |
Security Considerations
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
Advanced Usage
Custom Validation
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):
processed = super()._validate_client_metadata(metadata)
if 'client_name' in metadata:
if 'forbidden' in metadata['client_name'].lower():
raise ValidationError("Client name contains forbidden words")
return processed
Rate Limiting Example
Using 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):
pass
API Reference
DynamicClientRegistrationView
Main view class that handles client registration requests.
Methods
post(request)
- Handle registration requests
_validate_client_metadata(metadata)
- Override for custom validation
_create_application(metadata)
- Override for custom application creation
Testing
Run the tests:
pytest
Contributing
Contributions 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
License
This project is licensed under the MIT License - see the LICENSE file for details.
Related Projects
Support
If you encounter any issues or have questions:
Changelog
v0.1.0 (Initial Release)
- Initial implementation of RFC 7591 Dynamic Client Registration
- Support for open registration mode
- Comprehensive client metadata validation
- Integration with Django OAuth Toolkit Application model