OAuth2 Provider for Django web applications with complete server functionality, token management, and authorization endpoints.
—
Django OAuth Toolkit provides comprehensive web interface views for managing OAuth2 applications and user-authorized tokens. These class-based views integrate with Django's admin system and provide complete CRUD operations.
Web interface for OAuth2 client application management with full CRUD operations.
class ApplicationList(ListView):
"""
List view for OAuth2 applications.
URL: /o/applications/
Shows paginated list of applications owned by the current user.
Requires user authentication.
Template: oauth2_provider/application_list.html
Context: applications (queryset of Application objects)
"""
model = Application
template_name = "oauth2_provider/application_list.html"
context_object_name = "applications"
class ApplicationDetail(DetailView):
"""
Detail view for OAuth2 application.
URL: /o/applications/{pk}/
Shows detailed information about a specific application.
Only accessible to application owner.
Template: oauth2_provider/application_detail.html
Context: application (Application object)
"""
model = Application
template_name = "oauth2_provider/application_detail.html"
context_object_name = "application"
class ApplicationRegistration(CreateView):
"""
Create view for registering new OAuth2 applications.
URL: /o/applications/register/
Form for creating new OAuth2 client applications.
Automatically assigns current user as application owner.
Template: oauth2_provider/application_registration_form.html
Form: ApplicationForm
"""
model = Application
template_name = "oauth2_provider/application_registration_form.html"
form_class = ApplicationForm
class ApplicationUpdate(UpdateView):
"""
Update view for OAuth2 applications.
URL: /o/applications/{pk}/update/
Form for updating existing OAuth2 applications.
Only accessible to application owner.
Template: oauth2_provider/application_form.html
Form: ApplicationForm
"""
model = Application
template_name = "oauth2_provider/application_form.html"
form_class = ApplicationForm
class ApplicationDelete(DeleteView):
"""
Delete view for OAuth2 applications.
URL: /o/applications/{pk}/delete/
Confirmation form for deleting OAuth2 applications.
Only accessible to application owner.
Template: oauth2_provider/application_confirm_delete.html
Context: application (Application object)
"""
model = Application
template_name = "oauth2_provider/application_confirm_delete.html"
success_url = reverse_lazy("oauth2_provider:list")Web interface for users to manage their authorized OAuth2 tokens.
class AuthorizedTokensListView(ListView):
"""
List view for user's authorized OAuth2 tokens.
URL: /o/authorized_tokens/
Shows paginated list of access tokens authorized by current user.
Groups tokens by application and shows token details.
Template: oauth2_provider/authorized-tokens.html
Context: authorized_tokens (queryset of AccessToken objects)
"""
template_name = "oauth2_provider/authorized-tokens.html"
context_object_name = "authorized_tokens"
def get_queryset(self):
"""Get access tokens for current user"""
class AuthorizedTokenDeleteView(DeleteView):
"""
Delete view for revoking authorized tokens.
URL: /o/authorized_tokens/{pk}/delete/
Allows users to revoke their authorized tokens.
Revokes both access and refresh tokens.
Template: oauth2_provider/authorized-token-delete.html
Context: authorized_token (AccessToken object)
"""
template_name = "oauth2_provider/authorized-token-delete.html"
context_object_name = "authorized_token"
success_url = reverse_lazy("oauth2_provider:authorized-token-list")URL patterns for application and token management views.
management_urlpatterns = [
# Application management views
path("applications/", views.ApplicationList.as_view(), name="list"),
path("applications/register/", views.ApplicationRegistration.as_view(), name="register"),
path("applications/<slug:pk>/", views.ApplicationDetail.as_view(), name="detail"),
path("applications/<slug:pk>/delete/", views.ApplicationDelete.as_view(), name="delete"),
path("applications/<slug:pk>/update/", views.ApplicationUpdate.as_view(), name="update"),
# Token management views
path("authorized_tokens/", views.AuthorizedTokensListView.as_view(), name="authorized-token-list"),
path(
"authorized_tokens/<slug:pk>/delete/",
views.AuthorizedTokenDeleteView.as_view(),
name="authorized-token-delete",
),
]# urls.py
from django.urls import path, include
urlpatterns = [
# Include OAuth2 management URLs
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]
# This provides these management URLs:
# /o/applications/ - List applications
# /o/applications/register/ - Register new application
# /o/applications/{id}/ - View application details
# /o/applications/{id}/update/ - Update application
# /o/applications/{id}/delete/ - Delete application
# /o/authorized_tokens/ - List authorized tokens
# /o/authorized_tokens/{id}/delete/ - Revoke tokenfrom oauth2_provider.views.application import ApplicationRegistration
from oauth2_provider.forms import ApplicationForm
from django import forms
class CustomApplicationForm(ApplicationForm):
"""Custom form with additional fields"""
description = forms.CharField(
max_length=500,
required=False,
widget=forms.Textarea,
help_text="Describe your application"
)
class Meta(ApplicationForm.Meta):
fields = ApplicationForm.Meta.fields + ['description']
class CustomApplicationRegistration(ApplicationRegistration):
"""Custom registration view with additional fields"""
form_class = CustomApplicationForm
template_name = "myapp/custom_application_form.html"
def form_valid(self, form):
"""Add custom processing before saving"""
# Custom logic here
return super().form_valid(form)
# URL configuration
# path('custom/register/', CustomApplicationRegistration.as_view(), name='custom_register')<!-- templates/oauth2_provider/application_list.html -->
{% extends "base.html" %}
{% block content %}
<h1>My OAuth2 Applications</h1>
<a href="{% url 'oauth2_provider:register' %}" class="btn btn-primary">
Register New Application
</a>
<div class="applications">
{% for application in applications %}
<div class="application-card">
<h3>{{ application.name }}</h3>
<p><strong>Client ID:</strong> {{ application.client_id }}</p>
<p><strong>Type:</strong> {{ application.get_client_type_display }}</p>
<p><strong>Grant Type:</strong> {{ application.get_authorization_grant_type_display }}</p>
<div class="actions">
<a href="{% url 'oauth2_provider:detail' application.pk %}">View</a>
<a href="{% url 'oauth2_provider:update' application.pk %}">Edit</a>
<a href="{% url 'oauth2_provider:delete' application.pk %}">Delete</a>
</div>
</div>
{% empty %}
<p>No applications registered yet.</p>
{% endfor %}
</div>
{% endblock %}from oauth2_provider.views.application import ApplicationDetail
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
class SecureApplicationDetail(LoginRequiredMixin, ApplicationDetail):
"""Application detail view with enhanced security"""
def get_object(self, queryset=None):
"""Ensure user can only access their own applications"""
obj = super().get_object(queryset)
if obj.user != self.request.user:
raise PermissionDenied("You can only view your own applications")
return obj
class AdminApplicationList(ApplicationList):
"""Admin view to see all applications (requires staff permission)"""
def get_queryset(self):
"""Show all applications for staff users"""
if not self.request.user.is_staff:
raise PermissionDenied("Staff access required")
return Application.objects.all()from oauth2_provider.views.token import AuthorizedTokensListView
from django.db.models import Q
class EnhancedTokenListView(AuthorizedTokensListView):
"""Enhanced token list with filtering and search"""
def get_queryset(self):
"""Add filtering and search capabilities"""
queryset = super().get_queryset()
# Filter by application
app_filter = self.request.GET.get('application')
if app_filter:
queryset = queryset.filter(application__name__icontains=app_filter)
# Filter by scope
scope_filter = self.request.GET.get('scope')
if scope_filter:
queryset = queryset.filter(scope__icontains=scope_filter)
# Filter active tokens only
if self.request.GET.get('active_only'):
from django.utils import timezone
queryset = queryset.filter(expires__gt=timezone.now())
return queryset.order_by('-created')
def get_context_data(self, **kwargs):
"""Add filter context"""
context = super().get_context_data(**kwargs)
context['applications'] = Application.objects.filter(
accesstoken__user=self.request.user
).distinct()
return contextfrom oauth2_provider.views.application import ApplicationList
from django.http import JsonResponse
from django.views.generic import View
class ApplicationAPIView(View):
"""API endpoint for application management"""
def get(self, request):
"""Return applications as JSON"""
if not request.user.is_authenticated:
return JsonResponse({'error': 'Authentication required'}, status=401)
applications = Application.objects.filter(user=request.user)
data = []
for app in applications:
data.append({
'id': app.pk,
'name': app.name,
'client_id': app.client_id,
'client_type': app.client_type,
'authorization_grant_type': app.authorization_grant_type,
'created': app.created.isoformat(),
})
return JsonResponse({'applications': data})
class TokenAPIView(View):
"""API endpoint for token management"""
def get(self, request):
"""Return user's tokens as JSON"""
if not request.user.is_authenticated:
return JsonResponse({'error': 'Authentication required'}, status=401)
tokens = AccessToken.objects.filter(user=request.user)
data = []
for token in tokens:
data.append({
'id': token.pk,
'application': token.application.name,
'scope': token.scope,
'expires': token.expires.isoformat(),
'is_expired': token.is_expired(),
})
return JsonResponse({'tokens': data})
def delete(self, request, token_id):
"""Revoke specific token"""
if not request.user.is_authenticated:
return JsonResponse({'error': 'Authentication required'}, status=401)
try:
token = AccessToken.objects.get(pk=token_id, user=request.user)
token.revoke()
return JsonResponse({'message': 'Token revoked successfully'})
except AccessToken.DoesNotExist:
return JsonResponse({'error': 'Token not found'}, status=404)from oauth2_provider.views.token import AuthorizedTokensListView
from django.shortcuts import redirect
from django.contrib import messages
class BulkTokenManagementView(AuthorizedTokensListView):
"""Token list view with bulk operations"""
def post(self, request, *args, **kwargs):
"""Handle bulk operations"""
action = request.POST.get('action')
token_ids = request.POST.getlist('selected_tokens')
if not token_ids:
messages.error(request, 'No tokens selected')
return redirect('oauth2_provider:authorized-token-list')
tokens = AccessToken.objects.filter(
pk__in=token_ids,
user=request.user
)
if action == 'revoke_selected':
count = 0
for token in tokens:
token.revoke()
count += 1
messages.success(request, f'{count} tokens revoked successfully')
elif action == 'revoke_expired':
expired_tokens = tokens.filter(expires__lt=timezone.now())
count = expired_tokens.count()
for token in expired_tokens:
token.revoke()
messages.success(request, f'{count} expired tokens revoked')
return redirect('oauth2_provider:authorized-token-list')Install with Tessl CLI
npx tessl i tessl/pypi-django-oauth-toolkit